From 4ce8633ffbc40b6756d449637117b5e19b2dfb33 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Fri, 1 Dec 2023 09:37:59 -0800 Subject: [PATCH 01/40] Initial skeletal/scapholding for Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics boostrapper --- Roslyn.sln | 6 +++ ...odeAnalysis.LanguageServer.Protocol.csproj | 1 + .../Internal/OnInitializeServiceFactory.cs | 44 ++++++++++++++++++ .../VisualDiagnostics/InternalAPI.Shipped.txt | 1 + .../InternalAPI.Unshipped.txt | 3 ++ ...is.ExternalAccess.VisualDiagnostics.csproj | 46 +++++++++++++++++++ .../VisualDiagnostics/PublicAPI.Shipped.txt | 0 .../VisualDiagnostics/PublicAPI.Unshipped.txt | 0 .../Microsoft.CodeAnalysis.Workspaces.csproj | 1 + 9 files changed, 102 insertions(+) create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Shipped.txt create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Shipped.txt create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt diff --git a/Roslyn.sln b/Roslyn.sln index a803ad06d2b5f..70507f2956c2e 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -543,6 +543,7 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities", "src\Features\DiagnosticsTestUtilities\Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj", "{5BABC440-4F1B-46E8-9068-DD7F02ED25D3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.Test.Utilities", "src\Features\TestUtilities\Microsoft.CodeAnalysis.Features.Test.Utilities.csproj", "{5762E483-75CE-4328-A410-511F30737712}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{6D819E80-BA2F-4317-8368-37F8F4434D3A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1346,6 +1347,10 @@ Global {5762E483-75CE-4328-A410-511F30737712}.Debug|Any CPU.Build.0 = Debug|Any CPU {5762E483-75CE-4328-A410-511F30737712}.Release|Any CPU.ActiveCfg = Release|Any CPU {5762E483-75CE-4328-A410-511F30737712}.Release|Any CPU.Build.0 = Release|Any CPU + {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1595,6 +1600,7 @@ Global {4D9D7A28-BB44-4F3F-81DA-14F39B853718} = {CC126D03-7EAC-493F-B187-DCDEE1EF6A70} {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} + {6D819E80-BA2F-4317-8368-37F8F4434D3A} = {8977A560-45C2-4EC2-A849-97335B382C74} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29} diff --git a/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj b/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj index 2d42aa74a73b4..8a18503df47c1 100644 --- a/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj +++ b/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj @@ -81,6 +81,7 @@ + diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs new file mode 100644 index 0000000000000..405f4fc75b8d4 --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; + +[ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] +internal sealed class OnInitializedServiceFactory : ILspServiceFactory +{ + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public OnInitializedServiceFactory() + { + } + + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + { + return new OnInitializedService(); + } + + private class OnInitializedService : ILspService, IOnInitialized + { + public OnInitializedService() + { + } + + public Task OnInitializedAsync(LSP.ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Shipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Shipped.txt new file mode 100644 index 0000000000000..7dc5c58110bfa --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt new file mode 100644 index 0000000000000..00de2c57b988d --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.OnInitializedServiceFactory +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.OnInitializedServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.OnInitializedServiceFactory.OnInitializedServiceFactory() -> void \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj new file mode 100644 index 0000000000000..bb6fb3715027d --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -0,0 +1,46 @@ + + + + + Library + Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics + netstandard2.0 + + + true + Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics + + A supporting package for Visual Diagnostics: + https://github.com/dotnet/Roslyn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Shipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Shipped.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj index e6c9282509741..61979725f4679 100644 --- a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj @@ -133,6 +133,7 @@ + From 95080d00f30c4f8658a970cd899e1424c3914c55 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Wed, 10 Jan 2024 17:17:15 -0800 Subject: [PATCH 02/40] Initial checkin of EA.VisualDiagnostics --- .../Microsoft.CodeAnalysis.Features.csproj | 44 ++++ .../Services/AssemblyLoadContextWrapper.cs | 206 ++++++++++++++++++ .../IVisualDiagnosticsLanguageService.cs | 19 ++ .../Internal/HostDebuggerServices.cs | 46 ++++ .../Internal/OnInitializeServiceFactory.cs | 44 ---- .../VisualDiagnosticsServiceFactory.cs | 96 ++++++++ .../InternalAPI.Unshipped.txt | 7 +- ...is.ExternalAccess.VisualDiagnostics.csproj | 7 + .../VisualDiagnostics/PublicAPI.Unshipped.txt | 3 + 9 files changed, 425 insertions(+), 47 deletions(-) create mode 100644 src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs delete mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index 01f6ead6fa1ad..934734d271ab1 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -20,6 +20,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs new file mode 100644 index 0000000000000..d8b54db7f2d72 --- /dev/null +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs @@ -0,0 +1,206 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.Loader; +using Microsoft.Extensions.Logging; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer.Services +{ + internal sealed class AssemblyLoadContextWrapper : IDisposable + { + + // WORKAROUND for Roslyn bugs 71100 and 71101 + private static class AssemblyLoadHelper + { + private static readonly ConcurrentDictionary loadedAssemblies = new(StringComparer.OrdinalIgnoreCase); + static AssemblyLoadHelper() + { + // We might need to load System.Xaml for extensibility *.DesignTools.dll + Assembly? ResolveAssembly(object sender, ResolveEventArgs args) + { + string name = new AssemblyName(args.Name).Name; + if (name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + if (name.Equals("System.Xaml", StringComparison.OrdinalIgnoreCase) || + name.Equals("Microsoft.VisualStudio.Telemetry", StringComparison.OrdinalIgnoreCase) || + name.StartsWith("Microsoft.VisualStudio.DesignTools.", StringComparison.OrdinalIgnoreCase) || + name.StartsWith("Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", StringComparison.OrdinalIgnoreCase)) + { + Assembly? assembly = loadedAssemblies.GetOrAdd(name, AssemblyLoadHelper.EnsureAssembly); + return assembly; + } + + return null; + } + + AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; + } + + private static Assembly? EnsureAssembly(string name) + { + if (AssemblyLoadHelper.GetLoadedAssembly(name) is not Assembly assembly) + { + string path = Assembly.GetExecutingAssembly().Location; + string folder = Path.GetDirectoryName(path); + string assemblyPath = Path.Combine(folder, name + ".dll"); + if (File.Exists(assemblyPath)) + { + assembly = Assembly.LoadFrom(assemblyPath); + } + else + { + Debug.Fail($"Missing {assemblyPath}"); + return null; + } + } + + return assembly; + } + + private static Assembly? GetLoadedAssembly(string name) + { + // Find existing assembly + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly loadedAssembly in assemblies) + { + AssemblyName loadedAssemblyName = loadedAssembly.GetName(); + if (string.Equals(loadedAssemblyName.Name, name, StringComparison.Ordinal)) + { + return loadedAssembly; + } + } + + return null; + } + } + + static AssemblyLoadContextWrapper() + { + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(AssemblyLoadHelper).TypeHandle); + } + // WORKAROUND - END + + private AssemblyLoadContext? _assemblyLoadContext; + private readonly ImmutableDictionary _loadedAssemblies; + private readonly ILogger? _logger; + + private AssemblyLoadContextWrapper(AssemblyLoadContext assemblyLoadContext, ImmutableDictionary loadedFiles, ILogger? logger) + { + _assemblyLoadContext = assemblyLoadContext; + _loadedAssemblies = loadedFiles; + _logger = logger; + } + + public static bool TryLoadExtension(string assemblyFilePath, ILogger logger, [NotNullWhen(true)] out Assembly? assembly) + { + var dir = Path.GetDirectoryName(assemblyFilePath); + var fileName = Path.GetFileName(assemblyFilePath); + var fileNameNoExt = Path.GetFileNameWithoutExtension(assemblyFilePath); + + Contract.ThrowIfNull(dir); + Contract.ThrowIfNull(fileName); + Contract.ThrowIfNull(fileNameNoExt); + + var loadContext = TryCreate(fileNameNoExt, dir, logger); + if (loadContext != null) + { + assembly = loadContext.GetAssembly(fileName); + return true; + } + + assembly = null; + return false; + } + + public static AssemblyLoadContextWrapper? TryCreate(string name, string assembliesDirectoryPath, ILogger logger) + { + try + { + logger.LogTrace("[{name}] Loading assemblies in {assembliesDirectoryPath}", name, assembliesDirectoryPath); + + var loadContext = new AssemblyLoadContext(name); + var directory = new DirectoryInfo(assembliesDirectoryPath); + var builder = new Dictionary(); + foreach (var file in directory.GetFiles("*.dll")) + { + logger.LogTrace("[{name}] Loading {assemblyName}", loadContext.Name, file.Name); + builder.Add(file.Name, loadContext.LoadFromAssemblyPath(file.FullName)); + } + + return new AssemblyLoadContextWrapper(loadContext, builder.ToImmutableDictionary(), logger); + } + catch (Exception ex) + { + logger?.LogError(ex, "Failed to initialize AssemblyLoadContext {name}", name); + return null; + } + } + + public Assembly GetAssembly(string name) => _loadedAssemblies[name]; + + public MethodInfo? TryGetMethodInfo(string assemblyName, string className, string methodName) + { + try + { + return GetMethodInfo(assemblyName, className, methodName); + } + catch (Exception ex) + { + _logger?.LogError(ex, "Failed to get method information from {assembly} for {class}.{method}", assemblyName, className, methodName); + return null; + } + } + + public MethodInfo GetMethodInfo(string assemblyName, string className, string methodName) + { + var assembly = GetAssembly(assemblyName); + var completionHelperType = assembly.GetType(className); + if (completionHelperType == null) + { + throw new ArgumentException($"{assembly.FullName} assembly did not contain {className} class"); + } + var createCompletionProviderMethodInto = completionHelperType?.GetMethod(methodName); + if (createCompletionProviderMethodInto == null) + { + throw new ArgumentException($"{className} from {assembly.FullName} assembly did not contain {methodName} method"); + } + return createCompletionProviderMethodInto; + } + + public void Dispose() + { + _assemblyLoadContext?.Unload(); + _assemblyLoadContext = null; + } + + private sealed class AssemblyNameComparer : IEqualityComparer + { + public static readonly AssemblyNameComparer Default = new(); + + public bool Equals(AssemblyName? x, AssemblyName? y) + { + if (ReferenceEquals(x, y)) + return true; + + if (x == null || y == null) + return false; + + return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase) + && string.Equals(x.CultureName, y.CultureName, StringComparison.OrdinalIgnoreCase); + } + + public int GetHashCode(AssemblyName obj) + => HashCode.Combine( + StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name ?? string.Empty), + StringComparer.OrdinalIgnoreCase.GetHashCode(obj.CultureName ?? string.Empty)); + } + } +} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs new file mode 100644 index 0000000000000..7bc7c073fd67c --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts +{ + public interface IVisualDiagnosticsLanguageService : IWorkspaceService + { + public Task CreateDiagnosticsSessionAsync(Guid processId); + public Task StopDiagnosticsSessionAsync(Guid processId); + } +} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs new file mode 100644 index 0000000000000..bbc9c7b6f76a0 --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +//using System.Composition; +using System.ComponentModel.Composition; +using System.Text; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.ServiceHub.Framework; +using Microsoft.VisualStudio.Shell.ServiceBroker; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal +{ + internal interface IHostDebuggerServices + { + public void AttacheToDebuggerEvent(); + } + + [Export(typeof(IHostDebuggerServices))] + internal sealed class HostDebuggerServices : IHostDebuggerServices + { + IServiceBroker _serviceBroker; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public HostDebuggerServices( + [Import(typeof(SVsFullAccessServiceBroker))] + IServiceBroker serviceBroker) + { + _serviceBroker = serviceBroker; + } + + //[ImportingConstructor] + //[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + //public HostDebuggerServices() + //{ + //} + + public void AttacheToDebuggerEvent() + { + var serviceBroker = _serviceBroker; + } + } +} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs deleted file mode 100644 index 405f4fc75b8d4..0000000000000 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/OnInitializeServiceFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Composition; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServer; -using Microsoft.CodeAnalysis.LanguageServer.Handler; -using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.CodeAnalysis.Host.Mef; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; - -[ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] -internal sealed class OnInitializedServiceFactory : ILspServiceFactory -{ - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public OnInitializedServiceFactory() - { - } - - public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) - { - return new OnInitializedService(); - } - - private class OnInitializedService : ILspService, IOnInitialized - { - public OnInitializedService() - { - } - - public Task OnInitializedAsync(LSP.ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs new file mode 100644 index 0000000000000..9f60c21818a2d --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Contracts.EditAndContinue; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.ServiceHub.Framework; +using Microsoft.VisualStudio.Shell.ServiceBroker; +using Microsoft.VisualStudio.Utilities; +using Roslyn.Utilities; +using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; +using CompModel = System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal; +using System.Linq; +using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; + +[ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] +internal sealed class VIsualDiagnosticsServiceFactory : ILspServiceFactory +{ + private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; + private readonly Lazy _hostDebuggerServices; + + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + [ImportingConstructor] + public VIsualDiagnosticsServiceFactory( + LspWorkspaceRegistrationService lspWorkspaceRegistrationService, + Lazy hostDebuggerServices) + { + _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; + _hostDebuggerServices = hostDebuggerServices; + } + + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + { + var lspWorkspaceManager = lspServices.GetRequiredService(); + return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _hostDebuggerServices); + } + + private class OnInitializedService : ILspService, IOnInitialized, IDisposable + { + private readonly LspServices _lspServices; + private readonly LspWorkspaceManager _lspWorkspaceManager; + private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; + private readonly Lazy _hostDebuggerServices; + + public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, Lazy hostDebuggerServices) + { + _lspServices = lspServices; + _lspWorkspaceManager = lspWorkspaceManager; + _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; + _hostDebuggerServices = hostDebuggerServices; + } + + public void Dispose() + { + if (_lspWorkspaceManager != null) + { + _lspWorkspaceRegistrationService.LspSolutionChanged -= OnLspSolutionChanged; + } + } + + public Task OnInitializedAsync(LSP.ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) + { + _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; + return Task.CompletedTask; + } + + private void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) + { + if (e.DocumentId is not null && e.Kind is WorkspaceChangeKind.DocumentChanged) + { + _hostDebuggerServices.Value.AttacheToDebuggerEvent(); + var document = e.NewSolution.GetRequiredDocument(e.DocumentId); + var documentUri = document.GetURI(); + Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + if (workspace != null) + { + IVisualDiagnosticsLanguageService vdiagService = workspace.Services.GetService(); + if (vdiagService != null) + { + vdiagService.CreateDiagnosticsSessionAsync(Guid.NewGuid()); + } + } + } + } + } +} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 00de2c57b988d..b06c629da46e9 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -1,3 +1,4 @@ -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.OnInitializedServiceFactory -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.OnInitializedServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.OnInitializedServiceFactory.OnInitializedServiceFactory() -> void \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.HostDebuggerServices.AttacheToDebuggerEvent() -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VIsualDiagnosticsServiceFactory +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VIsualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VIsualDiagnosticsServiceFactory.VIsualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! hostDebuggerServices) -> void \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index bb6fb3715027d..c32926f234376 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -27,6 +27,13 @@ + + + + + + + diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt index e69de29bb2d1d..5fee97d2f0594 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.CreateDiagnosticsSessionAsync(System.Guid processId) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StopDiagnosticsSessionAsync(System.Guid processId) -> System.Threading.Tasks.Task \ No newline at end of file From a72da9870a2a4a2612a4a9b55791ddc76f584afc Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Wed, 10 Jan 2024 17:41:42 -0800 Subject: [PATCH 03/40] Add EA.VisualDiagnostics to the solution --- Roslyn.sln | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Roslyn.sln b/Roslyn.sln index 70507f2956c2e..bf5b076aefe9a 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -1,4 +1,7 @@ +<<<<<<< HEAD  +======= +>>>>>>> 8a98ca56667 (Add EA.VisualDiagnostics to the solution) Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31319.15 @@ -545,6 +548,8 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.Test.Utilities", "src\Features\TestUtilities\Microsoft.CodeAnalysis.Features.Test.Utilities.csproj", "{5762E483-75CE-4328-A410-511F30737712}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{6D819E80-BA2F-4317-8368-37F8F4434D3A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{567443BA-18A6-4A94-B078-A4988DD4016E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1351,6 +1356,10 @@ Global {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Release|Any CPU.ActiveCfg = Release|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Release|Any CPU.Build.0 = Release|Any CPU + {567443BA-18A6-4A94-B078-A4988DD4016E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {567443BA-18A6-4A94-B078-A4988DD4016E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {567443BA-18A6-4A94-B078-A4988DD4016E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {567443BA-18A6-4A94-B078-A4988DD4016E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1601,6 +1610,9 @@ Global {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {6D819E80-BA2F-4317-8368-37F8F4434D3A} = {8977A560-45C2-4EC2-A849-97335B382C74} + {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} + {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} + {567443BA-18A6-4A94-B078-A4988DD4016E} = {8977A560-45C2-4EC2-A849-97335B382C74} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29} From 60e0a1f679fe2a31bb53c4f8be15ae0e1696a079 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 22 Jan 2024 10:40:39 -0800 Subject: [PATCH 04/40] update to Workspage service --- Roslyn.sln | 13 ++++++++++++- global.json | 2 +- .../IVisualDiagnosticsLanguageService.cs | 1 - .../Internal/VisualDiagnosticsServiceFactory.cs | 15 +++++---------- ...alysis.ExternalAccess.VisualDiagnostics.csproj | 1 - 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Roslyn.sln b/Roslyn.sln index bf5b076aefe9a..b7789b2ab7d1c 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -1,7 +1,11 @@ <<<<<<< HEAD +<<<<<<< HEAD  ======= >>>>>>> 8a98ca56667 (Add EA.VisualDiagnostics to the solution) +======= + +>>>>>>> f602f2abe41 (update to Workspage service) Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31319.15 @@ -541,6 +545,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator", "src\Tools\ExternalAccess\EditorConfigGenerator\Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator.csproj", "{09AEDEE4-6358-47C9-8022-3BD37A518070}" EndProject +<<<<<<< HEAD Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestBuildProject", "src\VisualStudio\IntegrationTest\IntegrationTestBuildProject.csproj", "{4D9D7A28-BB44-4F3F-81DA-14F39B853718}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities", "src\Features\DiagnosticsTestUtilities\Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj", "{5BABC440-4F1B-46E8-9068-DD7F02ED25D3}" @@ -549,6 +554,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Feat Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{6D819E80-BA2F-4317-8368-37F8F4434D3A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{567443BA-18A6-4A94-B078-A4988DD4016E}" +======= +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{6D819E80-BA2F-4317-8368-37F8F4434D3A}" +>>>>>>> f602f2abe41 (update to Workspage service) EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1606,6 +1614,7 @@ Global {B1481D94-682E-46EC-ADBE-A16EB46FEEE9} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5} {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD} = {8977A560-45C2-4EC2-A849-97335B382C74} {09AEDEE4-6358-47C9-8022-3BD37A518070} = {8977A560-45C2-4EC2-A849-97335B382C74} +<<<<<<< HEAD {4D9D7A28-BB44-4F3F-81DA-14F39B853718} = {CC126D03-7EAC-493F-B187-DCDEE1EF6A70} {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} @@ -1613,6 +1622,9 @@ Global {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {567443BA-18A6-4A94-B078-A4988DD4016E} = {8977A560-45C2-4EC2-A849-97335B382C74} +======= + {6D819E80-BA2F-4317-8368-37F8F4434D3A} = {8977A560-45C2-4EC2-A849-97335B382C74} +>>>>>>> f602f2abe41 (update to Workspage service) EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29} @@ -1686,7 +1698,6 @@ Global src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{dc8c78cc-b6fe-47bf-93b1-b65a1c67c08d}*SharedItemsImports = 5 src\Analyzers\VisualBasic\Tests\VisualBasicAnalyzers.UnitTests.projitems*{e512c6c1-f085-4ad7-b0d9-e8f1a0a2a510}*SharedItemsImports = 5 src\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{e58ee9d7-1239-4961-a0c1-f9ec3952c4c1}*SharedItemsImports = 5 - src\Analyzers\CSharp\Tests\CSharpAnalyzers.UnitTests.projitems*{e645b517-5766-46fb-aa4a-d4d30c9e3be6}*SharedItemsImports = 5 src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.projitems*{e8f0baa5-7327-43d1-9a51-644e81ae55f1}*SharedItemsImports = 13 src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{e919dd77-34f8-4f57-8058-4d3ff4c2b241}*SharedItemsImports = 13 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\VisualBasicWorkspaceExtensions.projitems*{e9dbfa41-7a9c-49be-bd36-fd71b31aa9fe}*SharedItemsImports = 13 diff --git a/global.json b/global.json index 5db0afcd2453a..7350da84c3166 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.100", + "version": "8.0.101", "allowPrerelease": false, "rollForward": "patch" }, diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index 7bc7c073fd67c..e0c431b26fa30 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -7,7 +7,6 @@ using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 9f60c21818a2d..ba296ef30a744 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -4,22 +4,17 @@ using System; using System.Composition; +using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Contracts.EditAndContinue; +using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; +using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Shell.ServiceBroker; -using Microsoft.VisualStudio.Utilities; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; -using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; -using CompModel = System.ComponentModel.Composition; -using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal; -using System.Linq; -using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; @@ -68,7 +63,7 @@ public void Dispose() } } - public Task OnInitializedAsync(LSP.ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) + public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; return Task.CompletedTask; diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index c32926f234376..3e949adf24207 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -26,7 +26,6 @@ - From d42ef44417bc920521239d66c662217aec8e871e Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Sun, 4 Feb 2024 13:55:06 -0800 Subject: [PATCH 05/40] First hook attempt to the IHotReloadSessionNotificationService --- Roslyn.sln | 46 +--------- eng/Directory.Packages.props | 4 +- global.json | 2 +- .../Services/AssemblyLoadContextWrapper.cs | 2 + .../Contracts/IBrokeredDebuggerServices.cs | 14 ++++ .../IVisualDiagnosticsLanguageService.cs | 2 + .../Internal/BrokeredDebuggerServices.cs | 83 +++++++++++++++++++ .../Internal/HostDebuggerServices.cs | 46 ---------- .../VisualDiagnosticsServiceFactory.cs | 41 ++++----- .../InternalAPI.Unshipped.txt | 15 +++- ...is.ExternalAccess.VisualDiagnostics.csproj | 8 +- .../VisualDiagnostics/PublicAPI.Unshipped.txt | 5 +- 12 files changed, 148 insertions(+), 120 deletions(-) create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs delete mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs diff --git a/Roslyn.sln b/Roslyn.sln index b7789b2ab7d1c..46e13381bb262 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -1,11 +1,3 @@ -<<<<<<< HEAD -<<<<<<< HEAD - -======= ->>>>>>> 8a98ca56667 (Add EA.VisualDiagnostics to the solution) -======= - ->>>>>>> f602f2abe41 (update to Workspage service) Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31319.15 @@ -545,19 +537,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator", "src\Tools\ExternalAccess\EditorConfigGenerator\Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator.csproj", "{09AEDEE4-6358-47C9-8022-3BD37A518070}" EndProject -<<<<<<< HEAD -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestBuildProject", "src\VisualStudio\IntegrationTest\IntegrationTestBuildProject.csproj", "{4D9D7A28-BB44-4F3F-81DA-14F39B853718}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities", "src\Features\DiagnosticsTestUtilities\Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj", "{5BABC440-4F1B-46E8-9068-DD7F02ED25D3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.Test.Utilities", "src\Features\TestUtilities\Microsoft.CodeAnalysis.Features.Test.Utilities.csproj", "{5762E483-75CE-4328-A410-511F30737712}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{6D819E80-BA2F-4317-8368-37F8F4434D3A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{567443BA-18A6-4A94-B078-A4988DD4016E}" -======= -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{6D819E80-BA2F-4317-8368-37F8F4434D3A}" ->>>>>>> f602f2abe41 (update to Workspage service) -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1348,26 +1329,10 @@ Global {09AEDEE4-6358-47C9-8022-3BD37A518070}.Debug|Any CPU.Build.0 = Debug|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.ActiveCfg = Release|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.Build.0 = Release|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Release|Any CPU.Build.0 = Release|Any CPU - {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Release|Any CPU.Build.0 = Release|Any CPU - {5762E483-75CE-4328-A410-511F30737712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5762E483-75CE-4328-A410-511F30737712}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5762E483-75CE-4328-A410-511F30737712}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5762E483-75CE-4328-A410-511F30737712}.Release|Any CPU.Build.0 = Release|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Release|Any CPU.ActiveCfg = Release|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Release|Any CPU.Build.0 = Release|Any CPU - {567443BA-18A6-4A94-B078-A4988DD4016E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {567443BA-18A6-4A94-B078-A4988DD4016E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {567443BA-18A6-4A94-B078-A4988DD4016E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {567443BA-18A6-4A94-B078-A4988DD4016E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1614,17 +1579,7 @@ Global {B1481D94-682E-46EC-ADBE-A16EB46FEEE9} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5} {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD} = {8977A560-45C2-4EC2-A849-97335B382C74} {09AEDEE4-6358-47C9-8022-3BD37A518070} = {8977A560-45C2-4EC2-A849-97335B382C74} -<<<<<<< HEAD - {4D9D7A28-BB44-4F3F-81DA-14F39B853718} = {CC126D03-7EAC-493F-B187-DCDEE1EF6A70} - {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} - {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} - {6D819E80-BA2F-4317-8368-37F8F4434D3A} = {8977A560-45C2-4EC2-A849-97335B382C74} - {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} - {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} - {567443BA-18A6-4A94-B078-A4988DD4016E} = {8977A560-45C2-4EC2-A849-97335B382C74} -======= {6D819E80-BA2F-4317-8368-37F8F4434D3A} = {8977A560-45C2-4EC2-A849-97335B382C74} ->>>>>>> f602f2abe41 (update to Workspage service) EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29} @@ -1698,6 +1653,7 @@ Global src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{dc8c78cc-b6fe-47bf-93b1-b65a1c67c08d}*SharedItemsImports = 5 src\Analyzers\VisualBasic\Tests\VisualBasicAnalyzers.UnitTests.projitems*{e512c6c1-f085-4ad7-b0d9-e8f1a0a2a510}*SharedItemsImports = 5 src\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{e58ee9d7-1239-4961-a0c1-f9ec3952c4c1}*SharedItemsImports = 5 + src\Analyzers\CSharp\Tests\CSharpAnalyzers.UnitTests.projitems*{e645b517-5766-46fb-aa4a-d4d30c9e3be6}*SharedItemsImports = 5 src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.projitems*{e8f0baa5-7327-43d1-9a51-644e81ae55f1}*SharedItemsImports = 13 src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{e919dd77-34f8-4f57-8058-4d3ff4c2b241}*SharedItemsImports = 13 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\VisualBasicWorkspaceExtensions.projitems*{e9dbfa41-7a9c-49be-bd36-fd71b31aa9fe}*SharedItemsImports = 13 diff --git a/eng/Directory.Packages.props b/eng/Directory.Packages.props index f5de301ea0523..3e8fafab6848e 100644 --- a/eng/Directory.Packages.props +++ b/eng/Directory.Packages.props @@ -119,8 +119,8 @@ - - + + diff --git a/global.json b/global.json index 7350da84c3166..5db0afcd2453a 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.101", + "version": "8.0.100", "allowPrerelease": false, "rollForward": "patch" }, diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs index d8b54db7f2d72..938387312688d 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Concurrent; using System.Collections.Immutable; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.Loader; diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs new file mode 100644 index 0000000000000..91c66db927735 --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.VisualStudio.Debugger.Contracts.HotReload; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts +{ + internal interface IBrokeredDebuggerServices + { + ValueTask HotReloadSessionNotificationService { get; } + } +} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index e0c431b26fa30..5abc17b5b5342 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -7,11 +7,13 @@ using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; +using Microsoft.VisualStudio.Debugger.Contracts.HotReload; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { public interface IVisualDiagnosticsLanguageService : IWorkspaceService { + public Task InitializeAsync(); public Task CreateDiagnosticsSessionAsync(Guid processId); public Task StopDiagnosticsSessionAsync(Guid processId); } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs new file mode 100644 index 0000000000000..38b6f17481d94 --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.ServiceHub.Framework; +using Microsoft.VisualStudio.Composition; +using Microsoft.VisualStudio.Debugger.Contracts.HotReload; +using Microsoft.VisualStudio.Shell.ServiceBroker; +using Nerdbank.Streams; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal +{ + [Export(typeof(IBrokeredDebuggerServices))] + internal sealed class BrokeredDebuggerServices : IBrokeredDebuggerServices, IDisposable + { + private static readonly ServiceRpcDescriptor HotReloadSessionNotificationServiceDescriptor = CreateDescriptor( + new(HotReloadSessionNotificationServiceInfo.Moniker, new Version(HotReloadSessionNotificationServiceInfo.Version)), + clientInterface: null); + + private CancellationToken _serviceBrokerToken = new CancellationToken(); + private readonly IServiceBroker _serviceBroker; + private IHotReloadSessionNotificationService? _hotReloadSessionNotificationService; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public BrokeredDebuggerServices( + [Import(typeof(SVsFullAccessServiceBroker))] + IServiceBroker serviceBroker) + { + _serviceBroker = serviceBroker; + _ = InitializeAsync(); + } + + public ValueTask HotReloadSessionNotificationService + { + get + { + if (_hotReloadSessionNotificationService == null) + { + InitializeAsync().ConfigureAwait(true); + } + + if (_hotReloadSessionNotificationService != null) + { + return new ValueTask(_hotReloadSessionNotificationService); + } + + return new ValueTask(); + } + } + + private async Task InitializeAsync() + { + if (_serviceBroker == null) + { + return; + } + + (_hotReloadSessionNotificationService as IDisposable)?.Dispose(); + + _hotReloadSessionNotificationService = await _serviceBroker.GetProxyAsync(HotReloadSessionNotificationServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); + } + + public void Dispose() + { + (_hotReloadSessionNotificationService as IDisposable)?.Dispose(); + } + + private static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker moniker, Type? clientInterface) => new ServiceJsonRpcDescriptor( + moniker, + clientInterface, + ServiceJsonRpcDescriptor.Formatters.MessagePack, + ServiceJsonRpcDescriptor.MessageDelimiters.BigEndianInt32LengthHeader, + new MultiplexingStream.Options { ProtocolMajorVersion = 3 }) + .WithExceptionStrategy(StreamJsonRpc.ExceptionProcessing.ISerializable); + } +} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs deleted file mode 100644 index bbc9c7b6f76a0..0000000000000 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/HostDebuggerServices.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -//using System.Composition; -using System.ComponentModel.Composition; -using System.Text; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Shell.ServiceBroker; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal -{ - internal interface IHostDebuggerServices - { - public void AttacheToDebuggerEvent(); - } - - [Export(typeof(IHostDebuggerServices))] - internal sealed class HostDebuggerServices : IHostDebuggerServices - { - IServiceBroker _serviceBroker; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public HostDebuggerServices( - [Import(typeof(SVsFullAccessServiceBroker))] - IServiceBroker serviceBroker) - { - _serviceBroker = serviceBroker; - } - - //[ImportingConstructor] - //[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - //public HostDebuggerServices() - //{ - //} - - public void AttacheToDebuggerEvent() - { - var serviceBroker = _serviceBroker; - } - } -} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index ba296ef30a744..9cbbbb11b6bfe 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -12,32 +12,32 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.VisualStudio.Debugger.Contracts.HotReload; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; [ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] -internal sealed class VIsualDiagnosticsServiceFactory : ILspServiceFactory +internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory { private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly Lazy _hostDebuggerServices; + private readonly Lazy _brokeredDebuggerServices; [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [ImportingConstructor] - public VIsualDiagnosticsServiceFactory( + public VisualDiagnosticsServiceFactory( LspWorkspaceRegistrationService lspWorkspaceRegistrationService, - Lazy hostDebuggerServices) + Lazy brokeredDebuggerServices) { _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; - _hostDebuggerServices = hostDebuggerServices; + _brokeredDebuggerServices = brokeredDebuggerServices; } public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) { var lspWorkspaceManager = lspServices.GetRequiredService(); - return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _hostDebuggerServices); + return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _brokeredDebuggerServices); } private class OnInitializedService : ILspService, IOnInitialized, IDisposable @@ -45,14 +45,14 @@ private class OnInitializedService : ILspService, IOnInitialized, IDisposable private readonly LspServices _lspServices; private readonly LspWorkspaceManager _lspWorkspaceManager; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly Lazy _hostDebuggerServices; + private readonly Lazy _brokeredDebuggerServices; - public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, Lazy hostDebuggerServices) + public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, Lazy brokeredDebuggerServices) { - _lspServices = lspServices; + _lspServices = lspServices; _lspWorkspaceManager = lspWorkspaceManager; _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; - _hostDebuggerServices = hostDebuggerServices; + _brokeredDebuggerServices = brokeredDebuggerServices; } public void Dispose() @@ -69,21 +69,22 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon return Task.CompletedTask; } - private void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) + private async void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) { if (e.DocumentId is not null && e.Kind is WorkspaceChangeKind.DocumentChanged) { - _hostDebuggerServices.Value.AttacheToDebuggerEvent(); - var document = e.NewSolution.GetRequiredDocument(e.DocumentId); - var documentUri = document.GetURI(); + IHotReloadSessionNotificationService notificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationService.ConfigureAwait(false); + if(notificationService != null) + { + CancellationToken token = new CancellationToken(); + HotReloadSessionInfo info = await notificationService.FetchHotReloadSessionInfoAsync(token); + } Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); if (workspace != null) { - IVisualDiagnosticsLanguageService vdiagService = workspace.Services.GetService(); - if (vdiagService != null) - { - vdiagService.CreateDiagnosticsSessionAsync(Guid.NewGuid()); - } + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); + visualDiagnosticsLanguageService?.InitializeAsync(); + visualDiagnosticsLanguageService?.CreateDiagnosticsSessionAsync(Guid.NewGuid()); } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index b06c629da46e9..ecd41a1f2abef 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -1,4 +1,11 @@ -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.HostDebuggerServices.AttacheToDebuggerEvent() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VIsualDiagnosticsServiceFactory -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VIsualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VIsualDiagnosticsServiceFactory.VIsualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! hostDebuggerServices) -> void \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.BrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.Dispose() -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices) -> void \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 3e949adf24207..09a54acd84d5d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -27,12 +27,13 @@ - + + @@ -49,4 +50,9 @@ + + + + + \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt index 5fee97d2f0594..bed646fa3a021 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt @@ -1,3 +1,6 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.CreateDiagnosticsSessionAsync(System.Guid processId) -> System.Threading.Tasks.Task -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StopDiagnosticsSessionAsync(System.Guid processId) -> System.Threading.Tasks.Task \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.InitializeAsync() -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StopDiagnosticsSessionAsync(System.Guid processId) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask \ No newline at end of file From f85c28099ad0773ad2086979a831244c60cf94cc Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Sun, 4 Feb 2024 14:20:07 -0800 Subject: [PATCH 06/40] Remove the workaround --- .../Services/AssemblyLoadContextWrapper.cs | 75 ------------------- 1 file changed, 75 deletions(-) diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs index 938387312688d..28b2c6a0c51bf 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs @@ -15,81 +15,6 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Services { internal sealed class AssemblyLoadContextWrapper : IDisposable { - - // WORKAROUND for Roslyn bugs 71100 and 71101 - private static class AssemblyLoadHelper - { - private static readonly ConcurrentDictionary loadedAssemblies = new(StringComparer.OrdinalIgnoreCase); - static AssemblyLoadHelper() - { - // We might need to load System.Xaml for extensibility *.DesignTools.dll - Assembly? ResolveAssembly(object sender, ResolveEventArgs args) - { - string name = new AssemblyName(args.Name).Name; - if (name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - if (name.Equals("System.Xaml", StringComparison.OrdinalIgnoreCase) || - name.Equals("Microsoft.VisualStudio.Telemetry", StringComparison.OrdinalIgnoreCase) || - name.StartsWith("Microsoft.VisualStudio.DesignTools.", StringComparison.OrdinalIgnoreCase) || - name.StartsWith("Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", StringComparison.OrdinalIgnoreCase)) - { - Assembly? assembly = loadedAssemblies.GetOrAdd(name, AssemblyLoadHelper.EnsureAssembly); - return assembly; - } - - return null; - } - - AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; - } - - private static Assembly? EnsureAssembly(string name) - { - if (AssemblyLoadHelper.GetLoadedAssembly(name) is not Assembly assembly) - { - string path = Assembly.GetExecutingAssembly().Location; - string folder = Path.GetDirectoryName(path); - string assemblyPath = Path.Combine(folder, name + ".dll"); - if (File.Exists(assemblyPath)) - { - assembly = Assembly.LoadFrom(assemblyPath); - } - else - { - Debug.Fail($"Missing {assemblyPath}"); - return null; - } - } - - return assembly; - } - - private static Assembly? GetLoadedAssembly(string name) - { - // Find existing assembly - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly loadedAssembly in assemblies) - { - AssemblyName loadedAssemblyName = loadedAssembly.GetName(); - if (string.Equals(loadedAssemblyName.Name, name, StringComparison.Ordinal)) - { - return loadedAssembly; - } - } - - return null; - } - } - - static AssemblyLoadContextWrapper() - { - System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(AssemblyLoadHelper).TypeHandle); - } - // WORKAROUND - END - private AssemblyLoadContext? _assemblyLoadContext; private readonly ImmutableDictionary _loadedAssemblies; private readonly ILogger? _logger; From e0800d2879fc603d0c44b7f66a32f6685c4dade8 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Wed, 7 Feb 2024 11:41:12 -0800 Subject: [PATCH 07/40] debugging HotReloadSessionNotificationService --- .../Services/AssemblyLoadContextWrapper.cs | 74 +++++++++++++++++++ .../Contracts/IBrokeredDebuggerServices.cs | 5 +- .../Internal/BrokeredDebuggerServices.cs | 51 ++++++++----- .../VisualDiagnosticsServiceFactory.cs | 59 +++++++++++++-- .../InternalAPI.Unshipped.txt | 10 ++- 5 files changed, 172 insertions(+), 27 deletions(-) diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs index 28b2c6a0c51bf..153ba18fa55cf 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs @@ -19,6 +19,80 @@ internal sealed class AssemblyLoadContextWrapper : IDisposable private readonly ImmutableDictionary _loadedAssemblies; private readonly ILogger? _logger; + // WORKAROUND for Roslyn bugs 71100 and 71101 + private static class AssemblyLoadHelper + { + private static readonly ConcurrentDictionary loadedAssemblies = new(StringComparer.OrdinalIgnoreCase); + static AssemblyLoadHelper() + { + // We might need to load System.Xaml for extensibility *.DesignTools.dll + Assembly? ResolveAssembly(object sender, ResolveEventArgs args) + { + string name = new AssemblyName(args.Name).Name; + if (name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + if (name.Equals("System.Xaml", StringComparison.OrdinalIgnoreCase) || + name.Equals("Microsoft.VisualStudio.Telemetry", StringComparison.OrdinalIgnoreCase) || + name.StartsWith("Microsoft.VisualStudio.DesignTools.", StringComparison.OrdinalIgnoreCase) || + name.StartsWith("Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", StringComparison.OrdinalIgnoreCase)) + { + Assembly? assembly = loadedAssemblies.GetOrAdd(name, AssemblyLoadHelper.EnsureAssembly); + return assembly; + } + + return null; + } + + AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; + } + + private static Assembly? EnsureAssembly(string name) + { + if (AssemblyLoadHelper.GetLoadedAssembly(name) is not Assembly assembly) + { + string path = Assembly.GetExecutingAssembly().Location; + string folder = Path.GetDirectoryName(path); + string assemblyPath = Path.Combine(folder, name + ".dll"); + if (File.Exists(assemblyPath)) + { + assembly = Assembly.LoadFrom(assemblyPath); + } + else + { + Debug.Fail($"Missing {assemblyPath}"); + return null; + } + } + + return assembly; + } + + private static Assembly? GetLoadedAssembly(string name) + { + // Find existing assembly + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly loadedAssembly in assemblies) + { + AssemblyName loadedAssemblyName = loadedAssembly.GetName(); + if (string.Equals(loadedAssemblyName.Name, name, StringComparison.Ordinal)) + { + return loadedAssembly; + } + } + + return null; + } + } + + static AssemblyLoadContextWrapper() + { + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(AssemblyLoadHelper).TypeHandle); + } + // WORKAROUND - END + private AssemblyLoadContextWrapper(AssemblyLoadContext assemblyLoadContext, ImmutableDictionary loadedFiles, ILogger? logger) { _assemblyLoadContext = assemblyLoadContext; diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs index 91c66db927735..e8b05863e1f18 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs @@ -9,6 +9,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { internal interface IBrokeredDebuggerServices { - ValueTask HotReloadSessionNotificationService { get; } + Task HotReloadSessionNotificationServiceAsync(); + Task ManagedHotReloadAgentManagerServiceAsync(); + + Task ManagedHotReloadServiceAsync(); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs index 38b6f17481d94..40daf107561bf 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs @@ -23,9 +23,23 @@ internal sealed class BrokeredDebuggerServices : IBrokeredDebuggerServices, IDis new(HotReloadSessionNotificationServiceInfo.Moniker, new Version(HotReloadSessionNotificationServiceInfo.Version)), clientInterface: null); + // ManagedHotReloadService + private static readonly ServiceRpcDescriptor ManagedHotReloadAgentManagerServiceDescriptor = CreateDescriptor( + new(ManagedHotReloadAgentManagerServiceInfo.Moniker, new Version(ManagedHotReloadAgentManagerServiceInfo.Version)), + clientInterface: null); + + private const string ManagedHotReloadServiceInfo_Moniker = "Microsoft.VisualStudio.Debugger.ManagedHotReloadService"; + private const string ManagedHotReloadServiceInfo_Version = "0.1"; + private static readonly ServiceRpcDescriptor ManagedHotReloadServiceDescriptor = CreateDescriptor( + new(ManagedHotReloadServiceInfo_Moniker, new Version(ManagedHotReloadServiceInfo_Version)), + clientInterface: null); + private CancellationToken _serviceBrokerToken = new CancellationToken(); + private readonly IServiceBroker _serviceBroker; private IHotReloadSessionNotificationService? _hotReloadSessionNotificationService; + private IManagedHotReloadAgentManagerService? _ManagedHotReloadAgentManagerService; + private IManagedHotReloadService? _managedHotReloadService; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -34,42 +48,43 @@ public BrokeredDebuggerServices( IServiceBroker serviceBroker) { _serviceBroker = serviceBroker; - _ = InitializeAsync(); } - public ValueTask HotReloadSessionNotificationService + public async Task HotReloadSessionNotificationServiceAsync() { - get + if (_hotReloadSessionNotificationService == null) { - if (_hotReloadSessionNotificationService == null) - { - InitializeAsync().ConfigureAwait(true); - } + _hotReloadSessionNotificationService = await _serviceBroker.GetProxyAsync(HotReloadSessionNotificationServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); + } - if (_hotReloadSessionNotificationService != null) - { - return new ValueTask(_hotReloadSessionNotificationService); - } + return _hotReloadSessionNotificationService; + } - return new ValueTask(); + public async Task ManagedHotReloadAgentManagerServiceAsync() + { + if (_ManagedHotReloadAgentManagerService == null) + { + _ManagedHotReloadAgentManagerService = await _serviceBroker.GetProxyAsync(ManagedHotReloadAgentManagerServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); } + + return _ManagedHotReloadAgentManagerService; } - private async Task InitializeAsync() + public async Task ManagedHotReloadServiceAsync() { - if (_serviceBroker == null) + if (_managedHotReloadService == null) { - return; + _managedHotReloadService = await _serviceBroker.GetProxyAsync(ManagedHotReloadServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); } - (_hotReloadSessionNotificationService as IDisposable)?.Dispose(); - - _hotReloadSessionNotificationService = await _serviceBroker.GetProxyAsync(HotReloadSessionNotificationServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); + return _managedHotReloadService; } public void Dispose() { (_hotReloadSessionNotificationService as IDisposable)?.Dispose(); + (_ManagedHotReloadAgentManagerService as IDisposable)?.Dispose(); + (_managedHotReloadService as IDisposable)?.Dispose(); } private static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker moniker, Type? clientInterface) => new ServiceJsonRpcDescriptor( diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 9cbbbb11b6bfe..da9db78478527 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -4,6 +4,7 @@ using System; using System.Composition; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -46,13 +47,41 @@ private class OnInitializedService : ILspService, IOnInitialized, IDisposable private readonly LspWorkspaceManager _lspWorkspaceManager; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; private readonly Lazy _brokeredDebuggerServices; - + private System.Timers.Timer _timer; + + public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, Lazy brokeredDebuggerServices) { _lspServices = lspServices; _lspWorkspaceManager = lspWorkspaceManager; _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; _brokeredDebuggerServices = brokeredDebuggerServices; + _timer = new System.Timers.Timer(); + _timer.Interval = 1000; + _timer.Elapsed += _timer_Elapsed; + } + + private async void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + IManagedHotReloadService? manageHotReloadService = await _brokeredDebuggerServices.Value.ManagedHotReloadServiceAsync().ConfigureAwait(false); + if (manageHotReloadService != null) + { + Debug.WriteLine("IManagedHotReloadService Broker Proxy Available"); + } + else + { + Debug.WriteLine("IManagedHotReloadService Broker Proxy Not Yet Available"); + } + + IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); + if (hotReloadSessionNotificationService != null) + { + Debug.WriteLine("hotReloadSessionNotificationService Broker Proxy Available"); + } + else + { + Debug.WriteLine("hotReloadSessionNotificationService Broker Proxy Not Yet Available"); + } } public void Dispose() @@ -65,7 +94,8 @@ public void Dispose() public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { - _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; + // _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; + _timer.Start(); return Task.CompletedTask; } @@ -73,12 +103,26 @@ private async void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs { if (e.DocumentId is not null && e.Kind is WorkspaceChangeKind.DocumentChanged) { - IHotReloadSessionNotificationService notificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationService.ConfigureAwait(false); - if(notificationService != null) + IHotReloadSessionNotificationService? notificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); + if (notificationService != null) { CancellationToken token = new CancellationToken(); - HotReloadSessionInfo info = await notificationService.FetchHotReloadSessionInfoAsync(token); + HotReloadSessionInfo info = await notificationService.FetchHotReloadSessionInfoAsync(token).ConfigureAwait(false); } + + IManagedHotReloadAgentManagerService? managedHotReloadAgentManagerService = await _brokeredDebuggerServices.Value.ManagedHotReloadAgentManagerServiceAsync().ConfigureAwait(false); + if(managedHotReloadAgentManagerService != null) + { + CancellationToken token = new CancellationToken(); + } + + IManagedHotReloadService? manageHotReloadService = await _brokeredDebuggerServices.Value.ManagedHotReloadServiceAsync().ConfigureAwait(false); + if (manageHotReloadService != null) + { + CancellationToken token = new CancellationToken(); + } + + Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); if (workspace != null) { @@ -88,5 +132,10 @@ private async void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs } } } + + private Task InitializeHotReloadSessionNotificationService() + { + return Task.CompletedTask; + } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index ecd41a1f2abef..185b63226652c 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -1,11 +1,15 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.HotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.BrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.Dispose() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.HotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices) -> void \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices) -> void \ No newline at end of file From 4a9ef1190cdfaf8b7e536a817e59e0ff24923219 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Thu, 8 Feb 2024 18:34:59 -0800 Subject: [PATCH 08/40] Register HotReloadSessionNotificationService and ManagedHotReloadAgentManagerService to the service container --- SpellingExclusions.dic | 1 + .../BrokeredServices/Services/Descriptors.cs | 2 + .../Contracts/IBrokeredDebuggerServices.cs | 2 + .../IVisualDiagnosticsLanguageService.cs | 25 ++- .../Internal/BrokeredDebuggerServices.cs | 5 + .../VisualDiagnosticsServiceFactory.cs | 145 ++++++++++++------ .../InternalAPI.Unshipped.txt | 4 + .../VisualDiagnostics/PublicAPI.Unshipped.txt | 15 +- .../Remote/Core/BrokeredServiceDescriptors.cs | 2 + 9 files changed, 144 insertions(+), 57 deletions(-) diff --git a/SpellingExclusions.dic b/SpellingExclusions.dic index 44098153565f7..f1c6ee783e924 100644 --- a/SpellingExclusions.dic +++ b/SpellingExclusions.dic @@ -2,3 +2,4 @@ awaitable Refactorings Infos +Registar diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs index bd87c4f2b5155..59e4307831531 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs @@ -43,6 +43,8 @@ internal class Descriptors { RemoteProjectInitializationStatusService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, { BrokeredServiceDescriptors.SolutionSnapshotProvider.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, { BrokeredServiceDescriptors.DebuggerManagedHotReloadService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, + { BrokeredServiceDescriptors.HotReloadSessionNotificationService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, + { BrokeredServiceDescriptors.ManagedHotReloadAgentManagerService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, }.ToImmutableDictionary(); public static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker serviceMoniker) => new( diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs index e8b05863e1f18..9e152df36c828 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs @@ -3,12 +3,14 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; +using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Debugger.Contracts.HotReload; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { internal interface IBrokeredDebuggerServices { + Task ServiceBrokerAsync(); Task HotReloadSessionNotificationServiceAsync(); Task ManagedHotReloadAgentManagerServiceAsync(); diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index 5abc17b5b5342..a560f802cbeac 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -3,18 +3,31 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.VisualStudio.Debugger.Contracts.HotReload; +using Microsoft.ServiceHub.Framework; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { + [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0016:Add public types and members to the declared API", Justification = "False Positive asking to add TopString and =Operator")] + public readonly record struct ProcessInfo + { + public ProcessInfo(Guid processId, uint? localProcessId, string? path) + { + ProcessId = processId; + LocalProcessId = localProcessId; + Path = path; + } + public readonly Guid ProcessId { get; } + public readonly uint? LocalProcessId { get; } + public readonly string? Path { get; } + } + public interface IVisualDiagnosticsLanguageService : IWorkspaceService { - public Task InitializeAsync(); - public Task CreateDiagnosticsSessionAsync(Guid processId); - public Task StopDiagnosticsSessionAsync(Guid processId); + public Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); + public Task StartDebuggingSessionAsync(ProcessInfo info, CancellationToken token); + public Task StopDebuggingSessionAsync(ProcessInfo info, CancellationToken token); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs index 40daf107561bf..ae02941f13cab 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs @@ -50,6 +50,11 @@ public BrokeredDebuggerServices( _serviceBroker = serviceBroker; } + public Task ServiceBrokerAsync() + { + return Task.FromResult(_serviceBroker); + } + public async Task HotReloadSessionNotificationServiceAsync() { if (_hotReloadSessionNotificationService == null) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index da9db78478527..d244f21f19d04 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -3,16 +3,17 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Composition; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; -using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.ServiceHub.Framework; +using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; using Microsoft.VisualStudio.Debugger.Contracts.HotReload; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; @@ -41,14 +42,17 @@ public ILspService CreateILspService(LspServices lspServices, WellKnownLspServer return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _brokeredDebuggerServices); } - private class OnInitializedService : ILspService, IOnInitialized, IDisposable + private class OnInitializedService : ILspService, IOnInitialized, IObserver, IDisposable { private readonly LspServices _lspServices; private readonly LspWorkspaceManager _lspWorkspaceManager; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; private readonly Lazy _brokeredDebuggerServices; - private System.Timers.Timer _timer; - + private readonly Dictionary _visualDiagnosticsLanguageServiceRegistar; + private readonly System.Timers.Timer _timer; + private List _debugProcesses; + private CancellationToken _cancellationToken; + private IDisposable? _adviseHotReloadSessionNotificationService; public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, Lazy brokeredDebuggerServices) { @@ -58,84 +62,131 @@ public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWork _brokeredDebuggerServices = brokeredDebuggerServices; _timer = new System.Timers.Timer(); _timer.Interval = 1000; - _timer.Elapsed += _timer_Elapsed; + _timer.Elapsed += Timer_Elapsed; + _visualDiagnosticsLanguageServiceRegistar = new(); + _debugProcesses = new List(); } - private async void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + private async void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { - IManagedHotReloadService? manageHotReloadService = await _brokeredDebuggerServices.Value.ManagedHotReloadServiceAsync().ConfigureAwait(false); - if (manageHotReloadService != null) - { - Debug.WriteLine("IManagedHotReloadService Broker Proxy Available"); - } - else - { - Debug.WriteLine("IManagedHotReloadService Broker Proxy Not Yet Available"); - } - + // Let IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); if (hotReloadSessionNotificationService != null) { - Debug.WriteLine("hotReloadSessionNotificationService Broker Proxy Available"); - } - else - { - Debug.WriteLine("hotReloadSessionNotificationService Broker Proxy Not Yet Available"); + this._timer.Stop(); + _ = InitializeHotReloadSessionNotificationServiceAsync(hotReloadSessionNotificationService); } } public void Dispose() { - if (_lspWorkspaceManager != null) - { - _lspWorkspaceRegistrationService.LspSolutionChanged -= OnLspSolutionChanged; - } + _adviseHotReloadSessionNotificationService?.Dispose(); + (_brokeredDebuggerServices as IDisposable)?.Dispose(); } public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { - // _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; + _cancellationToken = cancellationToken; + // Start the timer because the broker service may not be initialize immediately, wait a couple millisec to get the debugger service _timer.Start(); return Task.CompletedTask; } - private async void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(HotReloadNotificationType value) + { + _ = HandleNotificationAsync(value); + } + + private async Task HandleNotificationAsync(HotReloadNotificationType value) { - if (e.DocumentId is not null && e.Kind is WorkspaceChangeKind.DocumentChanged) + IHotReloadSessionNotificationService? notificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); + if (notificationService != null) { - IHotReloadSessionNotificationService? notificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); - if (notificationService != null) + HotReloadSessionInfo info = await notificationService.FetchHotReloadSessionInfoAsync(_cancellationToken).ConfigureAwait(false); + switch (value) { - CancellationToken token = new CancellationToken(); - HotReloadSessionInfo info = await notificationService.FetchHotReloadSessionInfoAsync(token).ConfigureAwait(false); + case HotReloadNotificationType.Started: + await StartVisualDiagnosticsAsync(info).ConfigureAwait(false); + break; + case HotReloadNotificationType.Ended: + await StopVisualDiagnosticsAsync(info).ConfigureAwait(false); + break; } + } + } + + private async Task InitializeHotReloadSessionNotificationServiceAsync(IHotReloadSessionNotificationService hotReloadSessionNotificationService) + { + // Subscribe to the hotReload SessionNotification Service + _adviseHotReloadSessionNotificationService = await hotReloadSessionNotificationService.SubscribeAsync(this, _cancellationToken).ConfigureAwait(false); + } - IManagedHotReloadAgentManagerService? managedHotReloadAgentManagerService = await _brokeredDebuggerServices.Value.ManagedHotReloadAgentManagerServiceAsync().ConfigureAwait(false); - if(managedHotReloadAgentManagerService != null) + private async Task StartVisualDiagnosticsAsync(HotReloadSessionInfo info) + { + foreach (ManagedEditAndContinueProcessInfo processInfo in info.Processes) + { + ProcessInfo diagnosticsProcessInfo = new(processInfo.ProcessId, processInfo.LocalProcessId, processInfo.PathToTargetAssembly); + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = await EnsureVisualDiagnosticsLanguageServiceAsync(diagnosticsProcessInfo).ConfigureAwait(false); + if (visualDiagnosticsLanguageService != null) { - CancellationToken token = new CancellationToken(); + visualDiagnosticsLanguageService?.StartDebuggingSessionAsync(diagnosticsProcessInfo, _cancellationToken); + _debugProcesses.Add(diagnosticsProcessInfo); } + } + } - IManagedHotReloadService? manageHotReloadService = await _brokeredDebuggerServices.Value.ManagedHotReloadServiceAsync().ConfigureAwait(false); - if (manageHotReloadService != null) + private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) + { + // Info is the new list, so if process is in new list, no need to call StopDebugSessionAsync + foreach (ProcessInfo trackedDebuggedProcess in _debugProcesses) + { + if (!info.Processes.Any(item => item.ProcessId == trackedDebuggedProcess.ProcessId)) { - CancellationToken token = new CancellationToken(); + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = await EnsureVisualDiagnosticsLanguageServiceAsync(trackedDebuggedProcess).ConfigureAwait(false); + visualDiagnosticsLanguageService?.StopDebuggingSessionAsync(trackedDebuggedProcess, _cancellationToken); } + } + // Save the new list. + _debugProcesses = info.Processes.Select(_debugProcesses => new ProcessInfo(_debugProcesses.ProcessId, _debugProcesses.LocalProcessId, _debugProcesses.PathToTargetAssembly)).ToList(); + } - - Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); - if (workspace != null) + private async Task EnsureVisualDiagnosticsLanguageServiceAsync(ProcessInfo processInfo) + { + // TODO: Get the right workspace given the processInfo + Workspace workspace = ProcessInfoToWorkspace(processInfo); + if (workspace != null) + { + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = null; + if (!_visualDiagnosticsLanguageServiceRegistar.TryGetValue(workspace, out visualDiagnosticsLanguageService)) { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); - visualDiagnosticsLanguageService?.InitializeAsync(); - visualDiagnosticsLanguageService?.CreateDiagnosticsSessionAsync(Guid.NewGuid()); + visualDiagnosticsLanguageService = workspace.Services.GetService(); + IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.ServiceBrokerAsync().ConfigureAwait(false); + visualDiagnosticsLanguageService?.InitializeAsync(serviceProvider, _cancellationToken).ConfigureAwait(false); + if (visualDiagnosticsLanguageService != null) + { + _visualDiagnosticsLanguageServiceRegistar.Add(workspace, visualDiagnosticsLanguageService); + } } + // Could be null of we can't get the service + return visualDiagnosticsLanguageService; } + + return null; } - private Task InitializeHotReloadSessionNotificationService() + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Need to determine if multiple workspace exists in LSP server")] + private Workspace ProcessInfoToWorkspace(ProcessInfo processInfo) { - return Task.CompletedTask; + // Review: Does LSP supports more than one host workspace for a given process? For a given process name with path, should we retrieve the proper Workspace or it's always the host Workspace below? + return this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 185b63226652c..067fd802ea4f5 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -2,14 +2,18 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebug Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.HotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ServiceBrokerAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.BrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.Dispose() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.HotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ServiceBrokerAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices) -> void \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt index bed646fa3a021..f0cda7c2e5048 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt @@ -1,6 +1,13 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.CreateDiagnosticsSessionAsync(System.Guid processId) -> System.Threading.Tasks.Task -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.InitializeAsync() -> System.Threading.Tasks.Task -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StopDiagnosticsSessionAsync(System.Guid processId) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.InitializeAsync(Microsoft.ServiceHub.Framework.IServiceBroker serviceBroker, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StartDebuggingSessionAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StopDebuggingSessionAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.LocalProcessId.get -> uint? +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.Path.get -> string +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessId.get -> System.Guid +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo() -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo(System.Guid processId, uint? localProcessId, string path) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +override Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ToString() -> string \ No newline at end of file diff --git a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs index 71dfab8be7bec..bec99804ffd33 100644 --- a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs +++ b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs @@ -71,6 +71,8 @@ protected override JsonRpcConnection CreateConnection(JsonRpc jsonRpc) public static readonly ServiceRpcDescriptor SolutionSnapshotProvider = CreateClientServiceDescriptor("SolutionSnapshotProvider", new Version(0, 1)); public static readonly ServiceRpcDescriptor DebuggerManagedHotReloadService = CreateDebuggerServiceDescriptor("ManagedHotReloadService", new Version(0, 1)); public static readonly ServiceRpcDescriptor HotReloadLoggerService = CreateDebuggerServiceDescriptor("HotReloadLogger", new Version(0, 1)); + public static readonly ServiceRpcDescriptor HotReloadSessionNotificationService = CreateDebuggerServiceDescriptor("HotReloadSessionNotificationService", new Version(0, 1)); + public static readonly ServiceRpcDescriptor ManagedHotReloadAgentManagerService = CreateDebuggerServiceDescriptor("ManagedHotReloadAgentManagerService", new Version(0, 1)); public static ServiceMoniker CreateMoniker(string namespaceName, string componentName, string serviceName, Version? version) => new(namespaceName + "." + componentName + "." + serviceName, version); From 53ba8fbec3225be31f8b9571d9a28d80da3331c0 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Tue, 13 Feb 2024 14:26:19 -0800 Subject: [PATCH 09/40] fix versioning on newtonsoft and merge conflicts --- .../Services/AssemblyLoadContextWrapper.cs | 207 ------------------ ...is.ExternalAccess.VisualDiagnostics.csproj | 2 +- 2 files changed, 1 insertion(+), 208 deletions(-) delete mode 100644 src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs deleted file mode 100644 index 153ba18fa55cf..0000000000000 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Services/AssemblyLoadContextWrapper.cs +++ /dev/null @@ -1,207 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Concurrent; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using System.Runtime.Loader; -using Microsoft.Extensions.Logging; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.LanguageServer.Services -{ - internal sealed class AssemblyLoadContextWrapper : IDisposable - { - private AssemblyLoadContext? _assemblyLoadContext; - private readonly ImmutableDictionary _loadedAssemblies; - private readonly ILogger? _logger; - - // WORKAROUND for Roslyn bugs 71100 and 71101 - private static class AssemblyLoadHelper - { - private static readonly ConcurrentDictionary loadedAssemblies = new(StringComparer.OrdinalIgnoreCase); - static AssemblyLoadHelper() - { - // We might need to load System.Xaml for extensibility *.DesignTools.dll - Assembly? ResolveAssembly(object sender, ResolveEventArgs args) - { - string name = new AssemblyName(args.Name).Name; - if (name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - if (name.Equals("System.Xaml", StringComparison.OrdinalIgnoreCase) || - name.Equals("Microsoft.VisualStudio.Telemetry", StringComparison.OrdinalIgnoreCase) || - name.StartsWith("Microsoft.VisualStudio.DesignTools.", StringComparison.OrdinalIgnoreCase) || - name.StartsWith("Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", StringComparison.OrdinalIgnoreCase)) - { - Assembly? assembly = loadedAssemblies.GetOrAdd(name, AssemblyLoadHelper.EnsureAssembly); - return assembly; - } - - return null; - } - - AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; - } - - private static Assembly? EnsureAssembly(string name) - { - if (AssemblyLoadHelper.GetLoadedAssembly(name) is not Assembly assembly) - { - string path = Assembly.GetExecutingAssembly().Location; - string folder = Path.GetDirectoryName(path); - string assemblyPath = Path.Combine(folder, name + ".dll"); - if (File.Exists(assemblyPath)) - { - assembly = Assembly.LoadFrom(assemblyPath); - } - else - { - Debug.Fail($"Missing {assemblyPath}"); - return null; - } - } - - return assembly; - } - - private static Assembly? GetLoadedAssembly(string name) - { - // Find existing assembly - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly loadedAssembly in assemblies) - { - AssemblyName loadedAssemblyName = loadedAssembly.GetName(); - if (string.Equals(loadedAssemblyName.Name, name, StringComparison.Ordinal)) - { - return loadedAssembly; - } - } - - return null; - } - } - - static AssemblyLoadContextWrapper() - { - System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(AssemblyLoadHelper).TypeHandle); - } - // WORKAROUND - END - - private AssemblyLoadContextWrapper(AssemblyLoadContext assemblyLoadContext, ImmutableDictionary loadedFiles, ILogger? logger) - { - _assemblyLoadContext = assemblyLoadContext; - _loadedAssemblies = loadedFiles; - _logger = logger; - } - - public static bool TryLoadExtension(string assemblyFilePath, ILogger logger, [NotNullWhen(true)] out Assembly? assembly) - { - var dir = Path.GetDirectoryName(assemblyFilePath); - var fileName = Path.GetFileName(assemblyFilePath); - var fileNameNoExt = Path.GetFileNameWithoutExtension(assemblyFilePath); - - Contract.ThrowIfNull(dir); - Contract.ThrowIfNull(fileName); - Contract.ThrowIfNull(fileNameNoExt); - - var loadContext = TryCreate(fileNameNoExt, dir, logger); - if (loadContext != null) - { - assembly = loadContext.GetAssembly(fileName); - return true; - } - - assembly = null; - return false; - } - - public static AssemblyLoadContextWrapper? TryCreate(string name, string assembliesDirectoryPath, ILogger logger) - { - try - { - logger.LogTrace("[{name}] Loading assemblies in {assembliesDirectoryPath}", name, assembliesDirectoryPath); - - var loadContext = new AssemblyLoadContext(name); - var directory = new DirectoryInfo(assembliesDirectoryPath); - var builder = new Dictionary(); - foreach (var file in directory.GetFiles("*.dll")) - { - logger.LogTrace("[{name}] Loading {assemblyName}", loadContext.Name, file.Name); - builder.Add(file.Name, loadContext.LoadFromAssemblyPath(file.FullName)); - } - - return new AssemblyLoadContextWrapper(loadContext, builder.ToImmutableDictionary(), logger); - } - catch (Exception ex) - { - logger?.LogError(ex, "Failed to initialize AssemblyLoadContext {name}", name); - return null; - } - } - - public Assembly GetAssembly(string name) => _loadedAssemblies[name]; - - public MethodInfo? TryGetMethodInfo(string assemblyName, string className, string methodName) - { - try - { - return GetMethodInfo(assemblyName, className, methodName); - } - catch (Exception ex) - { - _logger?.LogError(ex, "Failed to get method information from {assembly} for {class}.{method}", assemblyName, className, methodName); - return null; - } - } - - public MethodInfo GetMethodInfo(string assemblyName, string className, string methodName) - { - var assembly = GetAssembly(assemblyName); - var completionHelperType = assembly.GetType(className); - if (completionHelperType == null) - { - throw new ArgumentException($"{assembly.FullName} assembly did not contain {className} class"); - } - var createCompletionProviderMethodInto = completionHelperType?.GetMethod(methodName); - if (createCompletionProviderMethodInto == null) - { - throw new ArgumentException($"{className} from {assembly.FullName} assembly did not contain {methodName} method"); - } - return createCompletionProviderMethodInto; - } - - public void Dispose() - { - _assemblyLoadContext?.Unload(); - _assemblyLoadContext = null; - } - - private sealed class AssemblyNameComparer : IEqualityComparer - { - public static readonly AssemblyNameComparer Default = new(); - - public bool Equals(AssemblyName? x, AssemblyName? y) - { - if (ReferenceEquals(x, y)) - return true; - - if (x == null || y == null) - return false; - - return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase) - && string.Equals(x.CultureName, y.CultureName, StringComparison.OrdinalIgnoreCase); - } - - public int GetHashCode(AssemblyName obj) - => HashCode.Combine( - StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name ?? string.Empty), - StringComparer.OrdinalIgnoreCase.GetHashCode(obj.CultureName ?? string.Empty)); - } - } -} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 09a54acd84d5d..bcf4c5a62b1a9 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -30,7 +30,7 @@ - + From cd9ac230a6b36f9b94f0fd6d929c187db0724e5c Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Thu, 15 Feb 2024 17:46:54 -0800 Subject: [PATCH 10/40] clean code, check for cancellation token, add EA.VisualDiagnostic a reference to LS server so that EA.VisualDiagnostics is part of the default ALC --- ...crosoft.CodeAnalysis.LanguageServer.csproj | 1 + .../Contracts/IBrokeredDebuggerServices.cs | 3 + .../IVisualDiagnosticsLanguageService.cs | 42 ++++++--- .../Internal/BrokeredDebuggerServices.cs | 1 + .../VisualDiagnosticsServiceFactory.cs | 94 +++++++++++++++---- 5 files changed, 110 insertions(+), 31 deletions(-) diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj index 67f57e759325d..88cfa85d45190 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj @@ -66,6 +66,7 @@ + diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs index 9e152df36c828..757387df2d1db 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs @@ -8,6 +8,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { + /// + /// Facade interface for getting various service brokers + /// internal interface IBrokeredDebuggerServices { Task ServiceBrokerAsync(); diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index a560f802cbeac..3900712d0ab31 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -10,24 +10,40 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0016:Add public types and members to the declared API", Justification = "False Positive asking to add TopString and =Operator")] - public readonly record struct ProcessInfo - { - public ProcessInfo(Guid processId, uint? localProcessId, string? path) - { - ProcessId = processId; - LocalProcessId = localProcessId; - Path = path; - } - public readonly Guid ProcessId { get; } - public readonly uint? LocalProcessId { get; } - public readonly string? Path { get; } - } + /// + /// Process Information + /// + /// Unique GUID that uniquely identify a process under a debug session + /// local process running on a host device, if the process running on a different host (like mobile device), this will be null + /// path to the process, this is guaranteed to not be null for local process, but could be null for mobile devices + [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0016:Add public types and members to the declared API", Justification = "False Positive, record is not well supported by the analyzer")] + public record struct ProcessInfo(Guid ProcessId, uint? LocalProcessId, string? Path); + /// + /// Workspace service responsible for starting a Visual Diagnostic session on the LSP server + /// public interface IVisualDiagnosticsLanguageService : IWorkspaceService { + /// + /// Initialize the diagnostic host + /// + /// Service broker + /// Cancellation token + /// public Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); + /// + /// Notifies the diagnostic host workspace service that a debugging session has started. + /// + /// Process information + /// Cancellation token + /// public Task StartDebuggingSessionAsync(ProcessInfo info, CancellationToken token); + /// + /// Notifies the diagnostic host workspace service that a debugging session has ended. + /// + /// Process information + /// Cancellation token + /// public Task StopDebuggingSessionAsync(ProcessInfo info, CancellationToken token); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs index ae02941f13cab..3b37b4d853c2b 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs @@ -19,6 +19,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal [Export(typeof(IBrokeredDebuggerServices))] internal sealed class BrokeredDebuggerServices : IBrokeredDebuggerServices, IDisposable { + // HotReloadSessionNotificationService private static readonly ServiceRpcDescriptor HotReloadSessionNotificationServiceDescriptor = CreateDescriptor( new(HotReloadSessionNotificationServiceInfo.Moniker, new Version(HotReloadSessionNotificationServiceInfo.Version)), clientInterface: null); diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index d244f21f19d04..f19fb9f487950 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Composition; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; @@ -20,6 +21,10 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; +/// +/// LSP Service responsible for hooking up to the debugger's broker IHotReloadSessionNotificationService +/// and listening to start/end debugging session delegating to IVisualDiagnosticsLanguageService workspace service +/// [ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory { @@ -48,8 +53,9 @@ private class OnInitializedService : ILspService, IOnInitialized, IObserver _brokeredDebuggerServices; - private readonly Dictionary _visualDiagnosticsLanguageServiceRegistar; + private readonly ConditionalWeakTable _visualDiagnosticsLanguageServiceTable; private readonly System.Timers.Timer _timer; + private static readonly object _lock = new object(); private List _debugProcesses; private CancellationToken _cancellationToken; private IDisposable? _adviseHotReloadSessionNotificationService; @@ -63,18 +69,16 @@ public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWork _timer = new System.Timers.Timer(); _timer.Interval = 1000; _timer.Elapsed += Timer_Elapsed; - _visualDiagnosticsLanguageServiceRegistar = new(); + _visualDiagnosticsLanguageServiceTable = new(); _debugProcesses = new List(); } - private async void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { - // Let - IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); - if (hotReloadSessionNotificationService != null) + // This timer is necessary because OnInitializedService + lock (_lock) { - this._timer.Stop(); - _ = InitializeHotReloadSessionNotificationServiceAsync(hotReloadSessionNotificationService); + _ = OnTimerElapsedAsync(); } } @@ -87,7 +91,9 @@ public void Dispose() public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { _cancellationToken = cancellationToken; - // Start the timer because the broker service may not be initialize immediately, wait a couple millisec to get the debugger service + // This is not ideal, OnInitializedAsync has no way to know when the service broker is ready to be queried + // We start a timer and wait rough a second to see if the broker gets initialized. + // TODO dabarbe: Service broker is initialized as part of another LSP service, not sure if there's a way for this service to have an api to await on? _timer.Start(); return Task.CompletedTask; } @@ -105,8 +111,38 @@ public void OnNext(HotReloadNotificationType value) _ = HandleNotificationAsync(value); } + private async Task OnTimerElapsedAsync() + { + if (_adviseHotReloadSessionNotificationService != null) + { + // just double make sure the timer is stopped + _timer.Stop(); + return; + } + + IBrokeredDebuggerServices broker = _brokeredDebuggerServices.Value; + + if (broker != null) + { + IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await broker.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); + if (hotReloadSessionNotificationService != null) + { + _adviseHotReloadSessionNotificationService = await InitializeHotReloadSessionNotificationServiceAsync(hotReloadSessionNotificationService).ConfigureAwait(false); + if (_adviseHotReloadSessionNotificationService != null) + { + _timer.Stop(); + } + } + } + } + private async Task HandleNotificationAsync(HotReloadNotificationType value) { + if (_cancellationToken.IsCancellationRequested) + { + return; + } + IHotReloadSessionNotificationService? notificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); if (notificationService != null) { @@ -123,14 +159,24 @@ private async Task HandleNotificationAsync(HotReloadNotificationType value) } } - private async Task InitializeHotReloadSessionNotificationServiceAsync(IHotReloadSessionNotificationService hotReloadSessionNotificationService) + private async Task InitializeHotReloadSessionNotificationServiceAsync(IHotReloadSessionNotificationService hotReloadSessionNotificationService) { + if (_cancellationToken.IsCancellationRequested) + { + return null; + } + // Subscribe to the hotReload SessionNotification Service - _adviseHotReloadSessionNotificationService = await hotReloadSessionNotificationService.SubscribeAsync(this, _cancellationToken).ConfigureAwait(false); + return await hotReloadSessionNotificationService.SubscribeAsync(this, _cancellationToken).ConfigureAwait(false); } private async Task StartVisualDiagnosticsAsync(HotReloadSessionInfo info) { + if (_cancellationToken.IsCancellationRequested) + { + return; + } + foreach (ManagedEditAndContinueProcessInfo processInfo in info.Processes) { ProcessInfo diagnosticsProcessInfo = new(processInfo.ProcessId, processInfo.LocalProcessId, processInfo.PathToTargetAssembly); @@ -145,6 +191,11 @@ private async Task StartVisualDiagnosticsAsync(HotReloadSessionInfo info) private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) { + if (_cancellationToken.IsCancellationRequested) + { + return; + } + // Info is the new list, so if process is in new list, no need to call StopDebugSessionAsync foreach (ProcessInfo trackedDebuggedProcess in _debugProcesses) { @@ -155,24 +206,29 @@ private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) } } // Save the new list. - _debugProcesses = info.Processes.Select(_debugProcesses => new ProcessInfo(_debugProcesses.ProcessId, _debugProcesses.LocalProcessId, _debugProcesses.PathToTargetAssembly)).ToList(); + _debugProcesses = info.Processes.Select(_debugProcess => new ProcessInfo(_debugProcess.ProcessId, _debugProcess.LocalProcessId, _debugProcess.PathToTargetAssembly)).ToList(); } private async Task EnsureVisualDiagnosticsLanguageServiceAsync(ProcessInfo processInfo) { - // TODO: Get the right workspace given the processInfo + if (_cancellationToken.IsCancellationRequested) + { + return null; + } + Workspace workspace = ProcessInfoToWorkspace(processInfo); if (workspace != null) { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = null; - if (!_visualDiagnosticsLanguageServiceRegistar.TryGetValue(workspace, out visualDiagnosticsLanguageService)) + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService; + if (!_visualDiagnosticsLanguageServiceTable.TryGetValue(workspace, out visualDiagnosticsLanguageService)) { visualDiagnosticsLanguageService = workspace.Services.GetService(); - IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.ServiceBrokerAsync().ConfigureAwait(false); - visualDiagnosticsLanguageService?.InitializeAsync(serviceProvider, _cancellationToken).ConfigureAwait(false); + if (visualDiagnosticsLanguageService != null) { - _visualDiagnosticsLanguageServiceRegistar.Add(workspace, visualDiagnosticsLanguageService); + IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.ServiceBrokerAsync().ConfigureAwait(false); + await visualDiagnosticsLanguageService.InitializeAsync(serviceProvider, _cancellationToken).ConfigureAwait(false); + _visualDiagnosticsLanguageServiceTable.Add(workspace, visualDiagnosticsLanguageService); } } // Could be null of we can't get the service @@ -186,6 +242,8 @@ private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) private Workspace ProcessInfoToWorkspace(ProcessInfo processInfo) { // Review: Does LSP supports more than one host workspace for a given process? For a given process name with path, should we retrieve the proper Workspace or it's always the host Workspace below? + // If the Host workspace provides access to a active set of source code projects and documents and their associated syntax trees, compilations and semantic models, and maps to the current opened solution in C# Dev Kit. + // Than I think we're good, are we? return this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); } } From f259f18a3bf125a63a275dd070dbe48f35e83180 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Tue, 27 Feb 2024 11:08:46 -0800 Subject: [PATCH 11/40] Update documentation --- .../VisualDiagnosticsServiceFactory.cs | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index f19fb9f487950..9485bde0173ff 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; using System.Composition; +using System.Data.SqlTypes; +using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; @@ -24,6 +26,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; /// /// LSP Service responsible for hooking up to the debugger's broker IHotReloadSessionNotificationService /// and listening to start/end debugging session delegating to IVisualDiagnosticsLanguageService workspace service +/// for debugger process referencing Maui.Essentials.dll /// [ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory @@ -75,7 +78,6 @@ public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWork private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { - // This timer is necessary because OnInitializedService lock (_lock) { _ = OnTimerElapsedAsync(); @@ -92,8 +94,8 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon { _cancellationToken = cancellationToken; // This is not ideal, OnInitializedAsync has no way to know when the service broker is ready to be queried - // We start a timer and wait rough a second to see if the broker gets initialized. - // TODO dabarbe: Service broker is initialized as part of another LSP service, not sure if there's a way for this service to have an api to await on? + // We start a timer and wait roughly a second to see if the broker gets initialized. + // TODO dabarbe: Service broker is initialized as part of another LSP service, not sure if there's a way await on, or having a task completion source? _timer.Start(); return Task.CompletedTask; } @@ -115,7 +117,7 @@ private async Task OnTimerElapsedAsync() { if (_adviseHotReloadSessionNotificationService != null) { - // just double make sure the timer is stopped + // Already initialized, just double make sure the timer is stopped _timer.Stop(); return; } @@ -127,6 +129,7 @@ private async Task OnTimerElapsedAsync() IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await broker.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); if (hotReloadSessionNotificationService != null) { + // We have the broker service, stop the timer _adviseHotReloadSessionNotificationService = await InitializeHotReloadSessionNotificationServiceAsync(hotReloadSessionNotificationService).ConfigureAwait(false); if (_adviseHotReloadSessionNotificationService != null) { @@ -216,7 +219,7 @@ private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) return null; } - Workspace workspace = ProcessInfoToWorkspace(processInfo); + Workspace? workspace = ProcessInfoToWorkspace(processInfo); if (workspace != null) { IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService; @@ -238,13 +241,47 @@ private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) return null; } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Need to determine if multiple workspace exists in LSP server")] - private Workspace ProcessInfoToWorkspace(ProcessInfo processInfo) + // This method helps reducing the memory footprint of EA.Diagnostics which an observer component looking + // at debugging executables only making sure that we end up loading IVisualDiagnosticsLanguageService workspace + // for debugged processes referencing Microsoft.Maui.Essentials.dll. + // This would include Maui, Maui Hybrid, iOS and Android projects. + private Workspace? ProcessInfoToWorkspace(ProcessInfo processInfo) { - // Review: Does LSP supports more than one host workspace for a given process? For a given process name with path, should we retrieve the proper Workspace or it's always the host Workspace below? - // If the Host workspace provides access to a active set of source code projects and documents and their associated syntax trees, compilations and semantic models, and maps to the current opened solution in C# Dev Kit. - // Than I think we're good, are we? - return this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + // + string? path = processInfo.Path; + string? directoryName = null; + if (path != null) + { + // for Mobile, the path is a path to assets which is not a path to a process + directoryName = Path.GetDirectoryName(path); + } + + Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + + Dictionary mauiEssentialProjects = new Dictionary(); + + if (workspace != null && !string.IsNullOrEmpty(directoryName)) + { + foreach (Project project in workspace.CurrentSolution.Projects) + { + // Workaround for single project with multiple TargetFrameworks, only the first framework project contains the Metadata References, the others don't + if (project.MetadataReferences != null && project.MetadataReferences.Any(item => item.Display != null && item.Display.ToLower().Contains("microsoft.maui.essentials.dll"))) + { + if (project.FilePath != null && !mauiEssentialProjects.ContainsKey(project.FilePath)) + { + mauiEssentialProjects.Add(project.FilePath, true); + } + } + + // Only return workspaces that utilize the Maui.Essentials library. + if (project.OutputFilePath != null && project.OutputFilePath.Contains(directoryName) && project.FilePath != null && mauiEssentialProjects.ContainsKey(project.FilePath)) + { + return workspace; + } + } + } + + return null; } } } From 90ab437708696eb2e3e061924bf80a69f624ddd5 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Tue, 27 Feb 2024 13:25:46 -0800 Subject: [PATCH 12/40] Fix merge conflicts --- Roslyn.sln | 21 +++++++++ SpellingExclusions.dic | 1 - .../Microsoft.CodeAnalysis.Features.csproj | 44 ------------------- .../VisualDiagnosticsServiceFactory.cs | 8 ++-- 4 files changed, 24 insertions(+), 50 deletions(-) diff --git a/Roslyn.sln b/Roslyn.sln index 46e13381bb262..ea00ff17562b1 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -537,6 +537,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator", "src\Tools\ExternalAccess\EditorConfigGenerator\Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator.csproj", "{09AEDEE4-6358-47C9-8022-3BD37A518070}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestBuildProject", "src\VisualStudio\IntegrationTest\IntegrationTestBuildProject.csproj", "{4D9D7A28-BB44-4F3F-81DA-14F39B853718}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities", "src\Features\DiagnosticsTestUtilities\Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj", "{5BABC440-4F1B-46E8-9068-DD7F02ED25D3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.Test.Utilities", "src\Features\TestUtilities\Microsoft.CodeAnalysis.Features.Test.Utilities.csproj", "{5762E483-75CE-4328-A410-511F30737712}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics", "src\Tools\ExternalAccess\VisualDiagnostics\Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj", "{6D819E80-BA2F-4317-8368-37F8F4434D3A}" EndProject Global @@ -1329,6 +1335,18 @@ Global {09AEDEE4-6358-47C9-8022-3BD37A518070}.Debug|Any CPU.Build.0 = Debug|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.ActiveCfg = Release|Any CPU {09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.Build.0 = Release|Any CPU + {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D9D7A28-BB44-4F3F-81DA-14F39B853718}.Release|Any CPU.Build.0 = Release|Any CPU + {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BABC440-4F1B-46E8-9068-DD7F02ED25D3}.Release|Any CPU.Build.0 = Release|Any CPU + {5762E483-75CE-4328-A410-511F30737712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5762E483-75CE-4328-A410-511F30737712}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5762E483-75CE-4328-A410-511F30737712}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5762E483-75CE-4328-A410-511F30737712}.Release|Any CPU.Build.0 = Release|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {6D819E80-BA2F-4317-8368-37F8F4434D3A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1579,6 +1597,9 @@ Global {B1481D94-682E-46EC-ADBE-A16EB46FEEE9} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5} {5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD} = {8977A560-45C2-4EC2-A849-97335B382C74} {09AEDEE4-6358-47C9-8022-3BD37A518070} = {8977A560-45C2-4EC2-A849-97335B382C74} + {4D9D7A28-BB44-4F3F-81DA-14F39B853718} = {CC126D03-7EAC-493F-B187-DCDEE1EF6A70} + {5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} + {5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {6D819E80-BA2F-4317-8368-37F8F4434D3A} = {8977A560-45C2-4EC2-A849-97335B382C74} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/SpellingExclusions.dic b/SpellingExclusions.dic index f1c6ee783e924..44098153565f7 100644 --- a/SpellingExclusions.dic +++ b/SpellingExclusions.dic @@ -2,4 +2,3 @@ awaitable Refactorings Infos -Registar diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index 3bef5294384bf..c5575614c4958 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -20,50 +20,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 9485bde0173ff..58fc93840a0c1 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -241,13 +241,11 @@ private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) return null; } - // This method helps reducing the memory footprint of EA.Diagnostics which an observer component looking - // at debugging executables only making sure that we end up loading IVisualDiagnosticsLanguageService workspace - // for debugged processes referencing Microsoft.Maui.Essentials.dll. - // This would include Maui, Maui Hybrid, iOS and Android projects. + // This method helps reducing the memory footprint of EA.Diagnostics by only making sure that we end up loading + // IVisualDiagnosticsLanguageService workspace for debugged processes referencing Microsoft.Maui.Essentials.dll. + // This would include Maui, Maui Hybrid, iOS and Android projects. private Workspace? ProcessInfoToWorkspace(ProcessInfo processInfo) { - // string? path = processInfo.Path; string? directoryName = null; if (path != null) From 8b1c86688de6d1ffba1a4339fb1add126e25e3b3 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Fri, 1 Mar 2024 14:53:01 -0800 Subject: [PATCH 13/40] Code Review changes and addtion to RequestDataBridgeConnectionAsync --- eng/config/PublishData.json | 1 + .../Contracts/IBrokeredDebuggerServices.cs | 9 ++++--- .../IVisualDiagnosticsLanguageService.cs | 24 +++++++++++++++---- .../Internal/BrokeredDebuggerServices.cs | 18 +++++++------- .../VisualDiagnosticsServiceFactory.cs | 14 +++++------ .../InternalAPI.Unshipped.txt | 20 ++++++++++++---- ...is.ExternalAccess.VisualDiagnostics.csproj | 10 +++----- .../VisualDiagnostics/PublicAPI.Unshipped.txt | 13 ---------- 8 files changed, 58 insertions(+), 51 deletions(-) diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index 7653ce3b21a5e..1cba0cc555bd8 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -79,6 +79,7 @@ "Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.TypeScript": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.UnitTesting": "vs-impl", + "Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.Xamarin.Remote": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.Xaml": "vs-impl", "Microsoft.CodeAnalysis.ExternalAccess.DotNetWatch": "vs-impl", diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs index 757387df2d1db..d846b38fbb491 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs @@ -13,10 +13,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts /// internal interface IBrokeredDebuggerServices { - Task ServiceBrokerAsync(); - Task HotReloadSessionNotificationServiceAsync(); - Task ManagedHotReloadAgentManagerServiceAsync(); - - Task ManagedHotReloadServiceAsync(); + Task GetServiceBrokerAsync(); + Task GetHotReloadSessionNotificationServiceAsync(); + Task GetManagedHotReloadAgentManagerServiceAsync(); + Task GetManagedHotReloadServiceAsync(); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index 3900712d0ab31..d009f952cc94d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -16,13 +16,17 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts /// Unique GUID that uniquely identify a process under a debug session /// local process running on a host device, if the process running on a different host (like mobile device), this will be null /// path to the process, this is guaranteed to not be null for local process, but could be null for mobile devices - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0016:Add public types and members to the declared API", Justification = "False Positive, record is not well supported by the analyzer")] - public record struct ProcessInfo(Guid ProcessId, uint? LocalProcessId, string? Path); + /// Connection Id identifying a data bridge connection to this process + [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "False Positive, record is not well supported by the analyzer")] + internal record struct ProcessInfo(Guid ProcessId, uint? LocalProcessId, string? Path, string? ConnectionId); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "False Positive, record is not well supported by the analyzer")] + internal record struct ConnectionInfo(string? ConnectionId, string? Handle, string? Address, uint? PortNumber); /// /// Workspace service responsible for starting a Visual Diagnostic session on the LSP server /// - public interface IVisualDiagnosticsLanguageService : IWorkspaceService + internal interface IVisualDiagnosticsLanguageService : IWorkspaceService { /// /// Initialize the diagnostic host @@ -31,19 +35,29 @@ public interface IVisualDiagnosticsLanguageService : IWorkspaceService /// Cancellation token /// public Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); + + /// + /// Request the creation of a data bridge connection info given a connection Id + /// + /// Unique identifiable token for a given connection + /// Cancellation token + /// a ConnectionInfo record + public Task RequestDataBridgeConnectionAsync(string connectionId, CancellationToken token); + /// /// Notifies the diagnostic host workspace service that a debugging session has started. /// /// Process information /// Cancellation token /// - public Task StartDebuggingSessionAsync(ProcessInfo info, CancellationToken token); + public Task HandleDiagnosticSessionStartAsync(ProcessInfo info, CancellationToken token); + /// /// Notifies the diagnostic host workspace service that a debugging session has ended. /// /// Process information /// Cancellation token /// - public Task StopDebuggingSessionAsync(ProcessInfo info, CancellationToken token); + public Task HandleDiagnosticSessionStopAsync(ProcessInfo info, CancellationToken token); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs index 3b37b4d853c2b..7ae83484ab617 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs @@ -39,7 +39,7 @@ internal sealed class BrokeredDebuggerServices : IBrokeredDebuggerServices, IDis private readonly IServiceBroker _serviceBroker; private IHotReloadSessionNotificationService? _hotReloadSessionNotificationService; - private IManagedHotReloadAgentManagerService? _ManagedHotReloadAgentManagerService; + private IManagedHotReloadAgentManagerService? _managedHotReloadAgentManagerService; private IManagedHotReloadService? _managedHotReloadService; [ImportingConstructor] @@ -51,12 +51,12 @@ public BrokeredDebuggerServices( _serviceBroker = serviceBroker; } - public Task ServiceBrokerAsync() + public Task GetServiceBrokerAsync() { return Task.FromResult(_serviceBroker); } - public async Task HotReloadSessionNotificationServiceAsync() + public async Task GetHotReloadSessionNotificationServiceAsync() { if (_hotReloadSessionNotificationService == null) { @@ -66,17 +66,17 @@ public Task ServiceBrokerAsync() return _hotReloadSessionNotificationService; } - public async Task ManagedHotReloadAgentManagerServiceAsync() + public async Task GetManagedHotReloadAgentManagerServiceAsync() { - if (_ManagedHotReloadAgentManagerService == null) + if (_managedHotReloadAgentManagerService == null) { - _ManagedHotReloadAgentManagerService = await _serviceBroker.GetProxyAsync(ManagedHotReloadAgentManagerServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); + _managedHotReloadAgentManagerService = await _serviceBroker.GetProxyAsync(ManagedHotReloadAgentManagerServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); } - return _ManagedHotReloadAgentManagerService; + return _managedHotReloadAgentManagerService; } - public async Task ManagedHotReloadServiceAsync() + public async Task GetManagedHotReloadServiceAsync() { if (_managedHotReloadService == null) { @@ -89,7 +89,7 @@ public Task ServiceBrokerAsync() public void Dispose() { (_hotReloadSessionNotificationService as IDisposable)?.Dispose(); - (_ManagedHotReloadAgentManagerService as IDisposable)?.Dispose(); + (_managedHotReloadAgentManagerService as IDisposable)?.Dispose(); (_managedHotReloadService as IDisposable)?.Dispose(); } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 58fc93840a0c1..5118b061a89dc 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -126,7 +126,7 @@ private async Task OnTimerElapsedAsync() if (broker != null) { - IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await broker.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); + IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await broker.GetHotReloadSessionNotificationServiceAsync().ConfigureAwait(false); if (hotReloadSessionNotificationService != null) { // We have the broker service, stop the timer @@ -146,7 +146,7 @@ private async Task HandleNotificationAsync(HotReloadNotificationType value) return; } - IHotReloadSessionNotificationService? notificationService = await _brokeredDebuggerServices.Value.HotReloadSessionNotificationServiceAsync().ConfigureAwait(false); + IHotReloadSessionNotificationService? notificationService = await _brokeredDebuggerServices.Value.GetHotReloadSessionNotificationServiceAsync().ConfigureAwait(false); if (notificationService != null) { HotReloadSessionInfo info = await notificationService.FetchHotReloadSessionInfoAsync(_cancellationToken).ConfigureAwait(false); @@ -182,11 +182,11 @@ private async Task StartVisualDiagnosticsAsync(HotReloadSessionInfo info) foreach (ManagedEditAndContinueProcessInfo processInfo in info.Processes) { - ProcessInfo diagnosticsProcessInfo = new(processInfo.ProcessId, processInfo.LocalProcessId, processInfo.PathToTargetAssembly); + ProcessInfo diagnosticsProcessInfo = new(processInfo.ProcessId, processInfo.LocalProcessId, processInfo.PathToTargetAssembly, null); IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = await EnsureVisualDiagnosticsLanguageServiceAsync(diagnosticsProcessInfo).ConfigureAwait(false); if (visualDiagnosticsLanguageService != null) { - visualDiagnosticsLanguageService?.StartDebuggingSessionAsync(diagnosticsProcessInfo, _cancellationToken); + visualDiagnosticsLanguageService?.HandleDiagnosticSessionStartAsync(diagnosticsProcessInfo, _cancellationToken); _debugProcesses.Add(diagnosticsProcessInfo); } } @@ -205,11 +205,11 @@ private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) if (!info.Processes.Any(item => item.ProcessId == trackedDebuggedProcess.ProcessId)) { IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = await EnsureVisualDiagnosticsLanguageServiceAsync(trackedDebuggedProcess).ConfigureAwait(false); - visualDiagnosticsLanguageService?.StopDebuggingSessionAsync(trackedDebuggedProcess, _cancellationToken); + visualDiagnosticsLanguageService?.HandleDiagnosticSessionStopAsync(trackedDebuggedProcess, _cancellationToken); } } // Save the new list. - _debugProcesses = info.Processes.Select(_debugProcess => new ProcessInfo(_debugProcess.ProcessId, _debugProcess.LocalProcessId, _debugProcess.PathToTargetAssembly)).ToList(); + _debugProcesses = info.Processes.Select(_debugProcess => new ProcessInfo(_debugProcess.ProcessId, _debugProcess.LocalProcessId, _debugProcess.PathToTargetAssembly, null)).ToList(); } private async Task EnsureVisualDiagnosticsLanguageServiceAsync(ProcessInfo processInfo) @@ -229,7 +229,7 @@ private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) if (visualDiagnosticsLanguageService != null) { - IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.ServiceBrokerAsync().ConfigureAwait(false); + IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.GetServiceBrokerAsync().ConfigureAwait(false); await visualDiagnosticsLanguageService.InitializeAsync(serviceProvider, _cancellationToken).ConfigureAwait(false); _visualDiagnosticsLanguageServiceTable.Add(workspace, visualDiagnosticsLanguageService); } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 067fd802ea4f5..40a8e54d9ca0e 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -1,8 +1,17 @@ +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo.ConnectionInfo() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.HotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.ServiceBrokerAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.HandleDiagnosticSessionStartAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.HandleDiagnosticSessionStopAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.InitializeAsync(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.RequestDataBridgeConnectionAsync(string! connectionId, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo(System.Guid ProcessId, uint? LocalProcessId, string? Path) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.BrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.Dispose() -> void @@ -16,4 +25,5 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices) -> void \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices) -> void +~override Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo.ToString() -> string \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index bcf4c5a62b1a9..2876a644835ab 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -19,12 +19,10 @@ - - - - + + - + @@ -53,6 +51,4 @@ - - \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt index f0cda7c2e5048..e69de29bb2d1d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/PublicAPI.Unshipped.txt @@ -1,13 +0,0 @@ -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.InitializeAsync(Microsoft.ServiceHub.Framework.IServiceBroker serviceBroker, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StartDebuggingSessionAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.StopDebuggingSessionAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.LocalProcessId.get -> uint? -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.Path.get -> string -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessId.get -> System.Guid -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo(System.Guid processId, uint? localProcessId, string path) -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask -override Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ToString() -> string \ No newline at end of file From 94080025cb2a0beaf4871bcb68c0ccd7656ffb08 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Wed, 6 Mar 2024 17:05:10 -0800 Subject: [PATCH 14/40] Fix BrokeredDebuggerServices internal Apis --- .../VisualDiagnostics/InternalAPI.Unshipped.txt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 40a8e54d9ca0e..7ef2ef122113f 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -15,12 +15,10 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.Pr Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.BrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.Dispose() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.HotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.ServiceBrokerAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.IBrokeredDebuggerServices.HotReloadSessionNotificationService.get -> System.Threading.Tasks.ValueTask +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory From 448fe282b5e410993cb78ca97f709453ee88b05a Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Thu, 7 Mar 2024 19:35:40 -0800 Subject: [PATCH 15/40] replace loc to SemaphoreSlim which is more thread safe for await functions --- .../VisualDiagnosticsServiceFactory.cs | 47 +++++++++++-------- ...is.ExternalAccess.VisualDiagnostics.csproj | 4 -- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 5118b061a89dc..f93cc45c0c38b 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -58,7 +58,7 @@ private class OnInitializedService : ILspService, IOnInitialized, IObserver _brokeredDebuggerServices; private readonly ConditionalWeakTable _visualDiagnosticsLanguageServiceTable; private readonly System.Timers.Timer _timer; - private static readonly object _lock = new object(); + private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); private List _debugProcesses; private CancellationToken _cancellationToken; private IDisposable? _adviseHotReloadSessionNotificationService; @@ -78,10 +78,8 @@ public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWork private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { - lock (_lock) - { - _ = OnTimerElapsedAsync(); - } + _timer.Stop(); + _ = OnTimerElapsedAsync(); } public void Dispose() @@ -115,27 +113,38 @@ public void OnNext(HotReloadNotificationType value) private async Task OnTimerElapsedAsync() { - if (_adviseHotReloadSessionNotificationService != null) + await _mutex.WaitAsync().ConfigureAwait(false); + try { - // Already initialized, just double make sure the timer is stopped - _timer.Stop(); - return; - } + // Already initialized + if (_adviseHotReloadSessionNotificationService != null) + { + return; + } - IBrokeredDebuggerServices broker = _brokeredDebuggerServices.Value; + IBrokeredDebuggerServices broker = _brokeredDebuggerServices.Value; - if (broker != null) - { - IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await broker.GetHotReloadSessionNotificationServiceAsync().ConfigureAwait(false); - if (hotReloadSessionNotificationService != null) + if (broker != null) { - // We have the broker service, stop the timer - _adviseHotReloadSessionNotificationService = await InitializeHotReloadSessionNotificationServiceAsync(hotReloadSessionNotificationService).ConfigureAwait(false); - if (_adviseHotReloadSessionNotificationService != null) + IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await broker.GetHotReloadSessionNotificationServiceAsync().ConfigureAwait(false); + if (hotReloadSessionNotificationService != null) { - _timer.Stop(); + // We have the broker service, stop the timer + _adviseHotReloadSessionNotificationService = await InitializeHotReloadSessionNotificationServiceAsync(hotReloadSessionNotificationService).ConfigureAwait(false); + if (_adviseHotReloadSessionNotificationService != null) + { + // Initialized + return; + } } } + + // We're not ready, re-start the timer + _timer.Start(); + } + finally + { + _mutex.Release(); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 2876a644835ab..d4459bda772ba 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -47,8 +47,4 @@ - - - - \ No newline at end of file From 5863a8a2c21ce39e79e6b97ffc33f9b043aba711 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Fri, 8 Mar 2024 13:59:29 -0800 Subject: [PATCH 16/40] Add IAsynchronousOperationListenerProvider and code review feedbacks --- .../Contracts/IBrokeredDebuggerServices.cs | 2 +- .../Internal/BrokeredDebuggerServices.cs | 6 +-- .../VisualDiagnosticsServiceFactory.cs | 39 ++++++++++++------- .../InternalAPI.Unshipped.txt | 26 ++++++------- ...is.ExternalAccess.VisualDiagnostics.csproj | 8 ++-- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs index d846b38fbb491..f889ebaa0338b 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts /// /// Facade interface for getting various service brokers /// - internal interface IBrokeredDebuggerServices + internal interface IVisualDiagnosticsBrokeredDebuggerServices { Task GetServiceBrokerAsync(); Task GetHotReloadSessionNotificationServiceAsync(); diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs index 7ae83484ab617..f6418680de68d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs @@ -16,8 +16,8 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal { - [Export(typeof(IBrokeredDebuggerServices))] - internal sealed class BrokeredDebuggerServices : IBrokeredDebuggerServices, IDisposable + [Export(typeof(IVisualDiagnosticsBrokeredDebuggerServices))] + internal sealed class VisualDiagnosticsBrokeredDebuggerServices : IVisualDiagnosticsBrokeredDebuggerServices, IDisposable { // HotReloadSessionNotificationService private static readonly ServiceRpcDescriptor HotReloadSessionNotificationServiceDescriptor = CreateDescriptor( @@ -44,7 +44,7 @@ internal sealed class BrokeredDebuggerServices : IBrokeredDebuggerServices, IDis [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public BrokeredDebuggerServices( + public VisualDiagnosticsBrokeredDebuggerServices( [Import(typeof(SVsFullAccessServiceBroker))] IServiceBroker serviceBroker) { diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index f93cc45c0c38b..e5f984691278a 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -3,21 +3,24 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; using System.Collections.Generic; using System.Composition; -using System.Data.SqlTypes; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; +using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; using Microsoft.VisualStudio.Debugger.Contracts.HotReload; +using Newtonsoft.Json.Linq; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; @@ -32,22 +35,25 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory { private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly Lazy _brokeredDebuggerServices; + private readonly Lazy _brokeredDebuggerServices; + private readonly IAsynchronousOperationListenerProvider _listenerProvider; [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [ImportingConstructor] public VisualDiagnosticsServiceFactory( LspWorkspaceRegistrationService lspWorkspaceRegistrationService, - Lazy brokeredDebuggerServices) + Lazy brokeredDebuggerServices, + IAsynchronousOperationListenerProvider listenerProvider) { _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; _brokeredDebuggerServices = brokeredDebuggerServices; + _listenerProvider = listenerProvider; } public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) { var lspWorkspaceManager = lspServices.GetRequiredService(); - return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _brokeredDebuggerServices); + return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _brokeredDebuggerServices, _listenerProvider); } private class OnInitializedService : ILspService, IOnInitialized, IObserver, IDisposable @@ -55,15 +61,20 @@ private class OnInitializedService : ILspService, IOnInitialized, IObserver _brokeredDebuggerServices; + private readonly Lazy _brokeredDebuggerServices; private readonly ConditionalWeakTable _visualDiagnosticsLanguageServiceTable; private readonly System.Timers.Timer _timer; private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); private List _debugProcesses; private CancellationToken _cancellationToken; private IDisposable? _adviseHotReloadSessionNotificationService; + private readonly IAsynchronousOperationListener _asyncListener; - public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, Lazy brokeredDebuggerServices) + public OnInitializedService(LspServices lspServices, + LspWorkspaceManager lspWorkspaceManager, + LspWorkspaceRegistrationService lspWorkspaceRegistrationService, + Lazy brokeredDebuggerServices, + IAsynchronousOperationListenerProvider listenerProvider) { _lspServices = lspServices; _lspWorkspaceManager = lspWorkspaceManager; @@ -74,12 +85,14 @@ public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWork _timer.Elapsed += Timer_Elapsed; _visualDiagnosticsLanguageServiceTable = new(); _debugProcesses = new List(); + _asyncListener = listenerProvider.GetListener(nameof(VisualDiagnosticsBrokeredDebuggerServices)); } private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { _timer.Stop(); - _ = OnTimerElapsedAsync(); + var token = _asyncListener.BeginAsyncOperation(nameof(OnInitializedService) + ".Timer_Elapsed"); + _ = OnTimerElapsedAsync().CompletesAsyncOperation(token); } public void Dispose() @@ -108,13 +121,13 @@ public void OnError(Exception error) public void OnNext(HotReloadNotificationType value) { - _ = HandleNotificationAsync(value); + var token = _asyncListener.BeginAsyncOperation(nameof(OnInitializedService) + ".OnNext"); + _ = HandleNotificationAsync(value).CompletesAsyncOperation(token); } private async Task OnTimerElapsedAsync() { - await _mutex.WaitAsync().ConfigureAwait(false); - try + using (await _mutex.DisposableWaitAsync().ConfigureAwait(false)) { // Already initialized if (_adviseHotReloadSessionNotificationService != null) @@ -122,7 +135,7 @@ private async Task OnTimerElapsedAsync() return; } - IBrokeredDebuggerServices broker = _brokeredDebuggerServices.Value; + IVisualDiagnosticsBrokeredDebuggerServices broker = _brokeredDebuggerServices.Value; if (broker != null) { @@ -142,10 +155,6 @@ private async Task OnTimerElapsedAsync() // We're not ready, re-start the timer _timer.Start(); } - finally - { - _mutex.Release(); - } } private async Task HandleNotificationAsync(HotReloadNotificationType value) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 7ef2ef122113f..9d1c317385401 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -1,10 +1,10 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo.ConnectionInfo() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IBrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.HandleDiagnosticSessionStartAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.HandleDiagnosticSessionStopAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! @@ -12,16 +12,16 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnos Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.RequestDataBridgeConnectionAsync(string! connectionId, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo(System.Guid ProcessId, uint? LocalProcessId, string? Path) -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.BrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.Dispose() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.BrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.Dispose() -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.VisualDiagnosticsBrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices) -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices, Microsoft.CodeAnalysis.Shared.TestHooks.IAsynchronousOperationListenerProvider! listenerProvider) -> void ~override Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo.ToString() -> string \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index d4459bda772ba..552e652e784c0 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -10,15 +10,13 @@ true Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics - A supporting package for Visual Diagnostics: - https://github.com/dotnet/Roslyn + A supporting package for Visual Studio CodeAnalysisDiagnostics: + https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/Xaml/Diagnostics/Source/CodeAnalysisDiagnostics - + From db7f504f4b48d5f1053716566ad54f101148492e Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Fri, 8 Mar 2024 14:21:29 -0800 Subject: [PATCH 17/40] Update Code Analyser bug for https://github.com/dotnet/roslyn-analyzers/issues/7237 --- .../Contracts/IVisualDiagnosticsLanguageService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index d009f952cc94d..4cdb14ef052c4 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -17,10 +17,10 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts /// local process running on a host device, if the process running on a different host (like mobile device), this will be null /// path to the process, this is guaranteed to not be null for local process, but could be null for mobile devices /// Connection Id identifying a data bridge connection to this process - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "False Positive, record is not well supported by the analyzer")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "https://github.com/dotnet/roslyn-analyzers/issues/7237")] internal record struct ProcessInfo(Guid ProcessId, uint? LocalProcessId, string? Path, string? ConnectionId); - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "False Positive, record is not well supported by the analyzer")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "https://github.com/dotnet/roslyn-analyzers/issues/7237")] internal record struct ConnectionInfo(string? ConnectionId, string? Handle, string? Address, uint? PortNumber); /// From 43555d244e9f7b5ec4d315a6c923dbbc22efc0ec Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 11 Mar 2024 11:54:56 -0700 Subject: [PATCH 18/40] Remove Microsoft.VisualStudio.Telemetry, Microsoft.ServiceHub.Client and Microsoft.ServiceHub.Framework reference --- ...rosoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 552e652e784c0..b55110703caa2 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -25,10 +25,7 @@ - - - From 19646424a65de79757853b6f46e6c592291d5350 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Tue, 12 Mar 2024 10:31:38 -0700 Subject: [PATCH 19/40] Moving All handling of broker service from EA.D into the implementation of IVisualDiagnosticsLanguageService --- .../IVisualDiagnosticsLanguageService.cs | 39 +--- ....cs => IVisualDiagnosticsServiceBroker.cs} | 5 +- .../Internal/BrokeredDebuggerServices.cs | 104 --------- .../VisualDiagnosticsServiceBroker.cs | 38 ++++ .../VisualDiagnosticsServiceFactory.cs | 206 ++---------------- 5 files changed, 57 insertions(+), 335 deletions(-) rename src/Tools/ExternalAccess/VisualDiagnostics/Contracts/{IBrokeredDebuggerServices.cs => IVisualDiagnosticsServiceBroker.cs} (63%) delete mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs create mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index 4cdb14ef052c4..73225b06135c4 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -10,23 +10,10 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { - /// - /// Process Information - /// - /// Unique GUID that uniquely identify a process under a debug session - /// local process running on a host device, if the process running on a different host (like mobile device), this will be null - /// path to the process, this is guaranteed to not be null for local process, but could be null for mobile devices - /// Connection Id identifying a data bridge connection to this process - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "https://github.com/dotnet/roslyn-analyzers/issues/7237")] - internal record struct ProcessInfo(Guid ProcessId, uint? LocalProcessId, string? Path, string? ConnectionId); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0051:Add internal types and members to the declared API", Justification = "https://github.com/dotnet/roslyn-analyzers/issues/7237")] - internal record struct ConnectionInfo(string? ConnectionId, string? Handle, string? Address, uint? PortNumber); - /// /// Workspace service responsible for starting a Visual Diagnostic session on the LSP server /// - internal interface IVisualDiagnosticsLanguageService : IWorkspaceService + internal interface IVisualDiagnosticsLanguageService : IWorkspaceService, IDisposable { /// /// Initialize the diagnostic host @@ -35,29 +22,5 @@ internal interface IVisualDiagnosticsLanguageService : IWorkspaceService /// Cancellation token /// public Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); - - /// - /// Request the creation of a data bridge connection info given a connection Id - /// - /// Unique identifiable token for a given connection - /// Cancellation token - /// a ConnectionInfo record - public Task RequestDataBridgeConnectionAsync(string connectionId, CancellationToken token); - - /// - /// Notifies the diagnostic host workspace service that a debugging session has started. - /// - /// Process information - /// Cancellation token - /// - public Task HandleDiagnosticSessionStartAsync(ProcessInfo info, CancellationToken token); - - /// - /// Notifies the diagnostic host workspace service that a debugging session has ended. - /// - /// Process information - /// Cancellation token - /// - public Task HandleDiagnosticSessionStopAsync(ProcessInfo info, CancellationToken token); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs similarity index 63% rename from src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs rename to src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs index f889ebaa0338b..6009d0f841f03 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IBrokeredDebuggerServices.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs @@ -9,13 +9,10 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { /// - /// Facade interface for getting various service brokers + /// Facade interface for getting broker service successfully through MEF /// internal interface IVisualDiagnosticsBrokeredDebuggerServices { Task GetServiceBrokerAsync(); - Task GetHotReloadSessionNotificationServiceAsync(); - Task GetManagedHotReloadAgentManagerServiceAsync(); - Task GetManagedHotReloadServiceAsync(); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs deleted file mode 100644 index f6418680de68d..0000000000000 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/BrokeredDebuggerServices.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.ComponentModel.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Composition; -using Microsoft.VisualStudio.Debugger.Contracts.HotReload; -using Microsoft.VisualStudio.Shell.ServiceBroker; -using Nerdbank.Streams; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal -{ - [Export(typeof(IVisualDiagnosticsBrokeredDebuggerServices))] - internal sealed class VisualDiagnosticsBrokeredDebuggerServices : IVisualDiagnosticsBrokeredDebuggerServices, IDisposable - { - // HotReloadSessionNotificationService - private static readonly ServiceRpcDescriptor HotReloadSessionNotificationServiceDescriptor = CreateDescriptor( - new(HotReloadSessionNotificationServiceInfo.Moniker, new Version(HotReloadSessionNotificationServiceInfo.Version)), - clientInterface: null); - - // ManagedHotReloadService - private static readonly ServiceRpcDescriptor ManagedHotReloadAgentManagerServiceDescriptor = CreateDescriptor( - new(ManagedHotReloadAgentManagerServiceInfo.Moniker, new Version(ManagedHotReloadAgentManagerServiceInfo.Version)), - clientInterface: null); - - private const string ManagedHotReloadServiceInfo_Moniker = "Microsoft.VisualStudio.Debugger.ManagedHotReloadService"; - private const string ManagedHotReloadServiceInfo_Version = "0.1"; - private static readonly ServiceRpcDescriptor ManagedHotReloadServiceDescriptor = CreateDescriptor( - new(ManagedHotReloadServiceInfo_Moniker, new Version(ManagedHotReloadServiceInfo_Version)), - clientInterface: null); - - private CancellationToken _serviceBrokerToken = new CancellationToken(); - - private readonly IServiceBroker _serviceBroker; - private IHotReloadSessionNotificationService? _hotReloadSessionNotificationService; - private IManagedHotReloadAgentManagerService? _managedHotReloadAgentManagerService; - private IManagedHotReloadService? _managedHotReloadService; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualDiagnosticsBrokeredDebuggerServices( - [Import(typeof(SVsFullAccessServiceBroker))] - IServiceBroker serviceBroker) - { - _serviceBroker = serviceBroker; - } - - public Task GetServiceBrokerAsync() - { - return Task.FromResult(_serviceBroker); - } - - public async Task GetHotReloadSessionNotificationServiceAsync() - { - if (_hotReloadSessionNotificationService == null) - { - _hotReloadSessionNotificationService = await _serviceBroker.GetProxyAsync(HotReloadSessionNotificationServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); - } - - return _hotReloadSessionNotificationService; - } - - public async Task GetManagedHotReloadAgentManagerServiceAsync() - { - if (_managedHotReloadAgentManagerService == null) - { - _managedHotReloadAgentManagerService = await _serviceBroker.GetProxyAsync(ManagedHotReloadAgentManagerServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); - } - - return _managedHotReloadAgentManagerService; - } - - public async Task GetManagedHotReloadServiceAsync() - { - if (_managedHotReloadService == null) - { - _managedHotReloadService = await _serviceBroker.GetProxyAsync(ManagedHotReloadServiceDescriptor, _serviceBrokerToken).ConfigureAwait(false); - } - - return _managedHotReloadService; - } - - public void Dispose() - { - (_hotReloadSessionNotificationService as IDisposable)?.Dispose(); - (_managedHotReloadAgentManagerService as IDisposable)?.Dispose(); - (_managedHotReloadService as IDisposable)?.Dispose(); - } - - private static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker moniker, Type? clientInterface) => new ServiceJsonRpcDescriptor( - moniker, - clientInterface, - ServiceJsonRpcDescriptor.Formatters.MessagePack, - ServiceJsonRpcDescriptor.MessageDelimiters.BigEndianInt32LengthHeader, - new MultiplexingStream.Options { ProtocolMajorVersion = 3 }) - .WithExceptionStrategy(StreamJsonRpc.ExceptionProcessing.ISerializable); - } -} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs new file mode 100644 index 0000000000000..a4420a1b72a5c --- /dev/null +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.ServiceHub.Framework; +using Microsoft.VisualStudio.Composition; +using Microsoft.VisualStudio.Shell.ServiceBroker; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal +{ + /// + /// This is a simple wrapper to succeed at getting the broker service using System.ComponentModel.Composition inside an LSP service OnInitialized factory + /// + [Export(typeof(IVisualDiagnosticsBrokeredDebuggerServices))] + internal sealed class VisualDiagnosticsBrokeredDebuggerServices : IVisualDiagnosticsBrokeredDebuggerServices + { + private readonly IServiceBroker _serviceBroker; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VisualDiagnosticsBrokeredDebuggerServices( + [Import(typeof(SVsFullAccessServiceBroker))] + IServiceBroker serviceBroker) + { + _serviceBroker = serviceBroker; + } + + public Task GetServiceBrokerAsync() + { + return Task.FromResult(_serviceBroker); + } + } +} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index e5f984691278a..cef3d834bf51b 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -3,12 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections; -using System.Collections.Generic; using System.Composition; -using System.IO; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; @@ -18,18 +14,14 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; -using Microsoft.VisualStudio.Debugger.Contracts.HotReload; -using Newtonsoft.Json.Linq; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; /// -/// LSP Service responsible for hooking up to the debugger's broker IHotReloadSessionNotificationService -/// and listening to start/end debugging session delegating to IVisualDiagnosticsLanguageService workspace service -/// for debugger process referencing Maui.Essentials.dll +/// LSP Service responsible for loading IVisualDiagnosticsLanguageService workspace service and delegate the broker service to the workspace service, +/// and handling MAUI XAML/C#/CSS/Razor Hot Reload support /// [ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory @@ -56,19 +48,17 @@ public ILspService CreateILspService(LspServices lspServices, WellKnownLspServer return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _brokeredDebuggerServices, _listenerProvider); } - private class OnInitializedService : ILspService, IOnInitialized, IObserver, IDisposable + private class OnInitializedService : ILspService, IOnInitialized, IDisposable { private readonly LspServices _lspServices; private readonly LspWorkspaceManager _lspWorkspaceManager; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; private readonly Lazy _brokeredDebuggerServices; - private readonly ConditionalWeakTable _visualDiagnosticsLanguageServiceTable; private readonly System.Timers.Timer _timer; private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); - private List _debugProcesses; - private CancellationToken _cancellationToken; - private IDisposable? _adviseHotReloadSessionNotificationService; private readonly IAsynchronousOperationListener _asyncListener; + private IVisualDiagnosticsLanguageService? _visualDiagnosticsLanguageServiceTable; + private CancellationToken _cancellationToken; public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, @@ -83,8 +73,6 @@ public OnInitializedService(LspServices lspServices, _timer = new System.Timers.Timer(); _timer.Interval = 1000; _timer.Elapsed += Timer_Elapsed; - _visualDiagnosticsLanguageServiceTable = new(); - _debugProcesses = new List(); _asyncListener = listenerProvider.GetListener(nameof(VisualDiagnosticsBrokeredDebuggerServices)); } @@ -97,8 +85,8 @@ private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) public void Dispose() { - _adviseHotReloadSessionNotificationService?.Dispose(); - (_brokeredDebuggerServices as IDisposable)?.Dispose(); + (_visualDiagnosticsLanguageServiceTable as IDisposable)?.Dispose(); + _timer?.Dispose(); } public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) @@ -111,44 +99,27 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon return Task.CompletedTask; } - public void OnCompleted() - { - } - - public void OnError(Exception error) - { - } - - public void OnNext(HotReloadNotificationType value) - { - var token = _asyncListener.BeginAsyncOperation(nameof(OnInitializedService) + ".OnNext"); - _ = HandleNotificationAsync(value).CompletesAsyncOperation(token); - } - private async Task OnTimerElapsedAsync() { using (await _mutex.DisposableWaitAsync().ConfigureAwait(false)) { - // Already initialized - if (_adviseHotReloadSessionNotificationService != null) - { - return; - } - IVisualDiagnosticsBrokeredDebuggerServices broker = _brokeredDebuggerServices.Value; if (broker != null) { - IHotReloadSessionNotificationService? hotReloadSessionNotificationService = await broker.GetHotReloadSessionNotificationServiceAsync().ConfigureAwait(false); - if (hotReloadSessionNotificationService != null) + // initialize VisualDiagnosticsLanguageService + Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + if (workspace != null) { - // We have the broker service, stop the timer - _adviseHotReloadSessionNotificationService = await InitializeHotReloadSessionNotificationServiceAsync(hotReloadSessionNotificationService).ConfigureAwait(false); - if (_adviseHotReloadSessionNotificationService != null) + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); + + if (visualDiagnosticsLanguageService != null) { - // Initialized - return; + IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.GetServiceBrokerAsync().ConfigureAwait(false); + await visualDiagnosticsLanguageService.InitializeAsync(serviceProvider, _cancellationToken).ConfigureAwait(false); + _visualDiagnosticsLanguageServiceTable = visualDiagnosticsLanguageService; } + return; } } @@ -156,148 +127,5 @@ private async Task OnTimerElapsedAsync() _timer.Start(); } } - - private async Task HandleNotificationAsync(HotReloadNotificationType value) - { - if (_cancellationToken.IsCancellationRequested) - { - return; - } - - IHotReloadSessionNotificationService? notificationService = await _brokeredDebuggerServices.Value.GetHotReloadSessionNotificationServiceAsync().ConfigureAwait(false); - if (notificationService != null) - { - HotReloadSessionInfo info = await notificationService.FetchHotReloadSessionInfoAsync(_cancellationToken).ConfigureAwait(false); - switch (value) - { - case HotReloadNotificationType.Started: - await StartVisualDiagnosticsAsync(info).ConfigureAwait(false); - break; - case HotReloadNotificationType.Ended: - await StopVisualDiagnosticsAsync(info).ConfigureAwait(false); - break; - } - } - } - - private async Task InitializeHotReloadSessionNotificationServiceAsync(IHotReloadSessionNotificationService hotReloadSessionNotificationService) - { - if (_cancellationToken.IsCancellationRequested) - { - return null; - } - - // Subscribe to the hotReload SessionNotification Service - return await hotReloadSessionNotificationService.SubscribeAsync(this, _cancellationToken).ConfigureAwait(false); - } - - private async Task StartVisualDiagnosticsAsync(HotReloadSessionInfo info) - { - if (_cancellationToken.IsCancellationRequested) - { - return; - } - - foreach (ManagedEditAndContinueProcessInfo processInfo in info.Processes) - { - ProcessInfo diagnosticsProcessInfo = new(processInfo.ProcessId, processInfo.LocalProcessId, processInfo.PathToTargetAssembly, null); - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = await EnsureVisualDiagnosticsLanguageServiceAsync(diagnosticsProcessInfo).ConfigureAwait(false); - if (visualDiagnosticsLanguageService != null) - { - visualDiagnosticsLanguageService?.HandleDiagnosticSessionStartAsync(diagnosticsProcessInfo, _cancellationToken); - _debugProcesses.Add(diagnosticsProcessInfo); - } - } - } - - private async Task StopVisualDiagnosticsAsync(HotReloadSessionInfo info) - { - if (_cancellationToken.IsCancellationRequested) - { - return; - } - - // Info is the new list, so if process is in new list, no need to call StopDebugSessionAsync - foreach (ProcessInfo trackedDebuggedProcess in _debugProcesses) - { - if (!info.Processes.Any(item => item.ProcessId == trackedDebuggedProcess.ProcessId)) - { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = await EnsureVisualDiagnosticsLanguageServiceAsync(trackedDebuggedProcess).ConfigureAwait(false); - visualDiagnosticsLanguageService?.HandleDiagnosticSessionStopAsync(trackedDebuggedProcess, _cancellationToken); - } - } - // Save the new list. - _debugProcesses = info.Processes.Select(_debugProcess => new ProcessInfo(_debugProcess.ProcessId, _debugProcess.LocalProcessId, _debugProcess.PathToTargetAssembly, null)).ToList(); - } - - private async Task EnsureVisualDiagnosticsLanguageServiceAsync(ProcessInfo processInfo) - { - if (_cancellationToken.IsCancellationRequested) - { - return null; - } - - Workspace? workspace = ProcessInfoToWorkspace(processInfo); - if (workspace != null) - { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService; - if (!_visualDiagnosticsLanguageServiceTable.TryGetValue(workspace, out visualDiagnosticsLanguageService)) - { - visualDiagnosticsLanguageService = workspace.Services.GetService(); - - if (visualDiagnosticsLanguageService != null) - { - IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.GetServiceBrokerAsync().ConfigureAwait(false); - await visualDiagnosticsLanguageService.InitializeAsync(serviceProvider, _cancellationToken).ConfigureAwait(false); - _visualDiagnosticsLanguageServiceTable.Add(workspace, visualDiagnosticsLanguageService); - } - } - // Could be null of we can't get the service - return visualDiagnosticsLanguageService; - } - - return null; - } - - // This method helps reducing the memory footprint of EA.Diagnostics by only making sure that we end up loading - // IVisualDiagnosticsLanguageService workspace for debugged processes referencing Microsoft.Maui.Essentials.dll. - // This would include Maui, Maui Hybrid, iOS and Android projects. - private Workspace? ProcessInfoToWorkspace(ProcessInfo processInfo) - { - string? path = processInfo.Path; - string? directoryName = null; - if (path != null) - { - // for Mobile, the path is a path to assets which is not a path to a process - directoryName = Path.GetDirectoryName(path); - } - - Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); - - Dictionary mauiEssentialProjects = new Dictionary(); - - if (workspace != null && !string.IsNullOrEmpty(directoryName)) - { - foreach (Project project in workspace.CurrentSolution.Projects) - { - // Workaround for single project with multiple TargetFrameworks, only the first framework project contains the Metadata References, the others don't - if (project.MetadataReferences != null && project.MetadataReferences.Any(item => item.Display != null && item.Display.ToLower().Contains("microsoft.maui.essentials.dll"))) - { - if (project.FilePath != null && !mauiEssentialProjects.ContainsKey(project.FilePath)) - { - mauiEssentialProjects.Add(project.FilePath, true); - } - } - - // Only return workspaces that utilize the Maui.Essentials library. - if (project.OutputFilePath != null && project.OutputFilePath.Contains(directoryName) && project.FilePath != null && mauiEssentialProjects.ContainsKey(project.FilePath)) - { - return workspace; - } - } - } - - return null; - } } } From af0c26b8abb671d1c8a4aeeccf577e280ab00346 Mon Sep 17 00:00:00 2001 From: Bret Johnson Date: Tue, 12 Mar 2024 18:53:15 -0400 Subject: [PATCH 20/40] Register MauiLaunchCustomizerServiceDescriptor remote service --- .../BrokeredServices/Services/Descriptors.cs | 1 + src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs index 59e4307831531..dd0618831e79c 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs @@ -45,6 +45,7 @@ internal class Descriptors { BrokeredServiceDescriptors.DebuggerManagedHotReloadService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, { BrokeredServiceDescriptors.HotReloadSessionNotificationService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, { BrokeredServiceDescriptors.ManagedHotReloadAgentManagerService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, + { BrokeredServiceDescriptors.MauiLaunchCustomizerServiceDescriptor.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, }.ToImmutableDictionary(); public static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker serviceMoniker) => new( diff --git a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs index bec99804ffd33..fff24e75125da 100644 --- a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs +++ b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs @@ -73,6 +73,7 @@ protected override JsonRpcConnection CreateConnection(JsonRpc jsonRpc) public static readonly ServiceRpcDescriptor HotReloadLoggerService = CreateDebuggerServiceDescriptor("HotReloadLogger", new Version(0, 1)); public static readonly ServiceRpcDescriptor HotReloadSessionNotificationService = CreateDebuggerServiceDescriptor("HotReloadSessionNotificationService", new Version(0, 1)); public static readonly ServiceRpcDescriptor ManagedHotReloadAgentManagerService = CreateDebuggerServiceDescriptor("ManagedHotReloadAgentManagerService", new Version(0, 1)); + public static readonly ServiceRpcDescriptor MauiLaunchCustomizerServiceDescriptor = CreateDebuggerServiceDescriptor("Maui.MauiLaunchCustomizerService", new Version(0, 1)); public static ServiceMoniker CreateMoniker(string namespaceName, string componentName, string serviceName, Version? version) => new(namespaceName + "." + componentName + "." + serviceName, version); From f65d0d9c7fcf7b3e78f6643ff928edcc149788b5 Mon Sep 17 00:00:00 2001 From: Bret Johnson Date: Wed, 13 Mar 2024 04:10:18 -0400 Subject: [PATCH 21/40] Remove unneeded using --- .../Contracts/IVisualDiagnosticsServiceBroker.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs index 6009d0f841f03..55549c88cbf1d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Debugger.Contracts.HotReload; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts { From cb48627d1460a5afb96b671ede0dd4f26ac6fb1e Mon Sep 17 00:00:00 2001 From: Bret Johnson Date: Fri, 15 Mar 2024 19:25:37 -0400 Subject: [PATCH 22/40] Update service descriptor definition --- src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs index fff24e75125da..3b26bcf0b55ff 100644 --- a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs +++ b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs @@ -73,7 +73,7 @@ protected override JsonRpcConnection CreateConnection(JsonRpc jsonRpc) public static readonly ServiceRpcDescriptor HotReloadLoggerService = CreateDebuggerServiceDescriptor("HotReloadLogger", new Version(0, 1)); public static readonly ServiceRpcDescriptor HotReloadSessionNotificationService = CreateDebuggerServiceDescriptor("HotReloadSessionNotificationService", new Version(0, 1)); public static readonly ServiceRpcDescriptor ManagedHotReloadAgentManagerService = CreateDebuggerServiceDescriptor("ManagedHotReloadAgentManagerService", new Version(0, 1)); - public static readonly ServiceRpcDescriptor MauiLaunchCustomizerServiceDescriptor = CreateDebuggerServiceDescriptor("Maui.MauiLaunchCustomizerService", new Version(0, 1)); + public static readonly ServiceRpcDescriptor MauiLaunchCustomizerServiceDescriptor = CreateMauiClientServiceDescriptor("MauiLaunchCustomizerService", new Version(0, 1)); public static ServiceMoniker CreateMoniker(string namespaceName, string componentName, string serviceName, Version? version) => new(namespaceName + "." + componentName + "." + serviceName, version); @@ -97,6 +97,13 @@ public static ServiceJsonRpcDescriptor CreateServerServiceDescriptor(string serv public static ServiceJsonRpcDescriptor CreateDebuggerServiceDescriptor(string serviceName, Version? version) => CreateDescriptor(CreateMoniker(VisualStudioComponentNamespace, DebuggerComponentName, serviceName, version)); + /// + /// Descriptor for services proferred by the MAUI client extension (implemented in TypeScript). + /// + public static ServiceJsonRpcDescriptor CreateMauiClientServiceDescriptor(string serviceName, Version? version) + => new ClientServiceDescriptor(CreateMoniker(VisualStudioComponentNamespace, "Maui", serviceName, version), clientInterface: null) + .WithExceptionStrategy(ExceptionProcessing.ISerializable); + private static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker moniker) => new ServiceJsonRpcDescriptor(moniker, Formatters.MessagePack, MessageDelimiters.BigEndianInt32LengthHeader) .WithExceptionStrategy(ExceptionProcessing.ISerializable); From 33526c383f824f679c60f5511dfad0aaed00ec45 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Sat, 16 Mar 2024 17:32:58 -0700 Subject: [PATCH 23/40] Export SVsBrokeredServiceContainer as a way to wait on a service broker container asynchornously --- .../BrokeredServices/ServiceBrokerFactory.cs | 30 +++++++--- .../VisualDiagnosticsServiceBroker.cs | 14 +++-- .../VisualDiagnosticsServiceFactory.cs | 58 ++++++++++++------- .../InternalAPI.Unshipped.txt | 6 +- 4 files changed, 69 insertions(+), 39 deletions(-) diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs index aa3787f934d57..08bc94d070588 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs @@ -26,7 +26,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.BrokeredServices; [Export] internal class ServiceBrokerFactory { - private BrokeredServiceContainer? _container; + private readonly TaskCompletionSource _container; private readonly ExportProvider _exportProvider; private Task _bridgeCompletionTask; private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); @@ -37,6 +37,7 @@ public ServiceBrokerFactory(ExportProvider exportProvider) { _exportProvider = exportProvider; _bridgeCompletionTask = Task.CompletedTask; + _container = new TaskCompletionSource(); } /// @@ -48,12 +49,19 @@ public ServiceBrokerFactory(ExportProvider exportProvider) /// /// Returns a full-access service broker, but will return null if we haven't yet connected to the Dev Kit broker. /// - public IServiceBroker? TryGetFullAccessServiceBroker() => _container?.GetFullAccessServiceBroker(); + public IServiceBroker? TryGetFullAccessServiceBroker() => _container.Task.IsCompletedSuccessfully ? _container.Task.Result?.GetFullAccessServiceBroker() : null; + + /// + /// Returns a full-access service broker container, that consuming code can await on until we connected to the Dev Kit broker + /// + [Export(typeof(SVsBrokeredServiceContainer))] + public Task BrokeredServiceContainerAsync => this.GetRequiredServiceBrokerContainerAsync(); public BrokeredServiceContainer GetRequiredServiceBrokerContainer() { - Contract.ThrowIfNull(_container); - return _container; + Contract.ThrowIfFalse(_container.Task.IsCompletedSuccessfully); + Contract.ThrowIfNull(_container.Task.Result); + return _container.Task.Result; } /// @@ -61,9 +69,10 @@ public BrokeredServiceContainer GetRequiredServiceBrokerContainer() /// public async Task CreateAsync() { - Contract.ThrowIfFalse(_container == null, "We should only create one container."); + Contract.ThrowIfFalse(!_container.Task.IsCompleted, "We should only create one container."); - _container = await BrokeredServiceContainer.CreateAsync(_exportProvider, _cancellationTokenSource.Token); + var container = await BrokeredServiceContainer.CreateAsync(_exportProvider, _cancellationTokenSource.Token); + _container.TrySetResult(container); } public async Task CreateAndConnectAsync(string brokeredServicePipeName) @@ -71,7 +80,7 @@ public async Task CreateAndConnectAsync(string brokeredServicePipeName) await CreateAsync(); var bridgeProvider = _exportProvider.GetExportedValue(); - _bridgeCompletionTask = bridgeProvider.SetupBrokeredServicesBridgeAsync(brokeredServicePipeName, _container!, _cancellationTokenSource.Token); + _bridgeCompletionTask = bridgeProvider.SetupBrokeredServicesBridgeAsync(brokeredServicePipeName, _container.Task.Result!, _cancellationTokenSource.Token); } public Task ShutdownAndWaitForCompletionAsync() @@ -82,5 +91,12 @@ public Task ShutdownAndWaitForCompletionAsync() // completed task set in the constructor, so the waiter no-ops. return _bridgeCompletionTask; } + + private async Task GetRequiredServiceBrokerContainerAsync() + { + // Caller of this method are expected to wait until the container is set by CreateAsync + var brokeredServiceContainer = await _container.Task.ConfigureAwait(false); + return brokeredServiceContainer; + } } #pragma warning restore RS0030 // Do not used banned APIs diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs index a4420a1b72a5c..8e5010f3a449a 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs @@ -19,20 +19,22 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal [Export(typeof(IVisualDiagnosticsBrokeredDebuggerServices))] internal sealed class VisualDiagnosticsBrokeredDebuggerServices : IVisualDiagnosticsBrokeredDebuggerServices { - private readonly IServiceBroker _serviceBroker; + private readonly Lazy> _container; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public VisualDiagnosticsBrokeredDebuggerServices( - [Import(typeof(SVsFullAccessServiceBroker))] - IServiceBroker serviceBroker) + [Import(typeof(SVsBrokeredServiceContainer))] + Lazy> serviceBroker) { - _serviceBroker = serviceBroker; + _container = serviceBroker; } - public Task GetServiceBrokerAsync() + public async Task GetServiceBrokerAsync() { - return Task.FromResult(_serviceBroker); + // Waiting on the container to be created + await _container.Value.ConfigureAwait(false); + return _container.Value.Result.GetFullAccessServiceBroker(); } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index cef3d834bf51b..16016808ea7bc 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -57,7 +57,7 @@ private class OnInitializedService : ILspService, IOnInitialized, IDisposable private readonly System.Timers.Timer _timer; private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); private readonly IAsynchronousOperationListener _asyncListener; - private IVisualDiagnosticsLanguageService? _visualDiagnosticsLanguageServiceTable; + private IVisualDiagnosticsLanguageService? _visualDiagnosticsLanguageService; private CancellationToken _cancellationToken; public OnInitializedService(LspServices lspServices, @@ -71,7 +71,7 @@ public OnInitializedService(LspServices lspServices, _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; _brokeredDebuggerServices = brokeredDebuggerServices; _timer = new System.Timers.Timer(); - _timer.Interval = 1000; + _timer.Interval = 500; _timer.Elapsed += Timer_Elapsed; _asyncListener = listenerProvider.GetListener(nameof(VisualDiagnosticsBrokeredDebuggerServices)); } @@ -85,46 +85,62 @@ private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) public void Dispose() { - (_visualDiagnosticsLanguageServiceTable as IDisposable)?.Dispose(); + (_visualDiagnosticsLanguageService as IDisposable)?.Dispose(); _timer?.Dispose(); } public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { _cancellationToken = cancellationToken; - // This is not ideal, OnInitializedAsync has no way to know when the service broker is ready to be queried - // We start a timer and wait roughly a second to see if the broker gets initialized. - // TODO dabarbe: Service broker is initialized as part of another LSP service, not sure if there's a way await on, or having a task completion source? + // TODO dabarbe: Calling ServiceBrokerFactory.GetRequiredServiceBrokerContainerAsync.ConfigureAwait(false); here prevents + // ServiceBrokerConnectHandler from being initialized. Not sure why? There's something in the synchronization context that + // prevents TaskCompletionSource tasks to run properly during the LSP initialization. Solution is to getting out of OnInitializedAsync and calling + // _brokeredDebuggerServices.Value.GetServiceBrokerAsync().ConfigureAwait(false) on the timer dispatcher, which is a separate synchronization context. This + // allows GetServiceBrokerAsync() to await until ServiceBrokerFactory.CreateAsync sets the container, and allowing the task completion source to resume _timer.Start(); return Task.CompletedTask; } private async Task OnTimerElapsedAsync() + { + await OnInitializeVisualDiagnosticsLanguageServiceAsync().ConfigureAwait(false); + } + + private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync() { using (await _mutex.DisposableWaitAsync().ConfigureAwait(false)) { - IVisualDiagnosticsBrokeredDebuggerServices broker = _brokeredDebuggerServices.Value; + if (_visualDiagnosticsLanguageService != null) + { + return; + } - if (broker != null) + IVisualDiagnosticsBrokeredDebuggerServices brokerService = _brokeredDebuggerServices.Value; + + if (brokerService != null) { - // initialize VisualDiagnosticsLanguageService - Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); - if (workspace != null) + // The broker service may be not available right await. That's because the broker service gets initialized + // when the C# DevKit is getting initialized in parallel. GetServiceBrokerAsync() will await until + // the container gets created. Once created, this task will resume. In case where C# Dev kit is not + // enabled, the service broker container will never be created and this task will never return, thus preventing + // us from creating the IVisualDiagnosticsLanguageService + IServiceBroker? serviceBroker = await brokerService.GetServiceBrokerAsync().ConfigureAwait(false); + if (serviceBroker != null) { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); - - if (visualDiagnosticsLanguageService != null) + // initialize VisualDiagnosticsLanguageService + Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + if (workspace != null) { - IServiceBroker? serviceProvider = await _brokeredDebuggerServices.Value.GetServiceBrokerAsync().ConfigureAwait(false); - await visualDiagnosticsLanguageService.InitializeAsync(serviceProvider, _cancellationToken).ConfigureAwait(false); - _visualDiagnosticsLanguageServiceTable = visualDiagnosticsLanguageService; + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); + + if (visualDiagnosticsLanguageService != null) + { + await visualDiagnosticsLanguageService.InitializeAsync(serviceBroker, _cancellationToken).ConfigureAwait(false); + _visualDiagnosticsLanguageService = visualDiagnosticsLanguageService; + } } - return; } } - - // We're not ready, re-start the timer - _timer.Start(); } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 9d1c317385401..0f90997e265b8 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -13,12 +13,8 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnos Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo(System.Guid ProcessId, uint? LocalProcessId, string? Path) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.Dispose() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.VisualDiagnosticsBrokeredDebuggerServices(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.VisualDiagnosticsBrokeredDebuggerServices(System.Lazy!>! serviceBroker) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory From c9cdb3a118d146b6789895b5aaa3aca0c6992b59 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 18 Mar 2024 09:28:19 -0700 Subject: [PATCH 24/40] Rename class to VisualDiagnosticsServiceBroker --- .../IVisualDiagnosticsServiceBroker.cs | 2 +- .../VisualDiagnosticsServiceBroker.cs | 6 +++--- .../VisualDiagnosticsServiceFactory.cs | 12 +++++------ .../InternalAPI.Unshipped.txt | 20 ++++++------------- 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs index 55549c88cbf1d..37a29d31e00e1 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts /// /// Facade interface for getting broker service successfully through MEF /// - internal interface IVisualDiagnosticsBrokeredDebuggerServices + internal interface IVisualDiagnosticsServiceBroker { Task GetServiceBrokerAsync(); } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs index 8e5010f3a449a..72364e437d19d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs @@ -16,14 +16,14 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal /// /// This is a simple wrapper to succeed at getting the broker service using System.ComponentModel.Composition inside an LSP service OnInitialized factory /// - [Export(typeof(IVisualDiagnosticsBrokeredDebuggerServices))] - internal sealed class VisualDiagnosticsBrokeredDebuggerServices : IVisualDiagnosticsBrokeredDebuggerServices + [Export(typeof(IVisualDiagnosticsServiceBroker))] + internal sealed class VisualDiagnosticsServiceBroker : IVisualDiagnosticsServiceBroker { private readonly Lazy> _container; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualDiagnosticsBrokeredDebuggerServices( + public VisualDiagnosticsServiceBroker( [Import(typeof(SVsBrokeredServiceContainer))] Lazy> serviceBroker) { diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 16016808ea7bc..4b804c68bbb2a 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -27,14 +27,14 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory { private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly Lazy _brokeredDebuggerServices; + private readonly Lazy _brokeredDebuggerServices; private readonly IAsynchronousOperationListenerProvider _listenerProvider; [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [ImportingConstructor] public VisualDiagnosticsServiceFactory( LspWorkspaceRegistrationService lspWorkspaceRegistrationService, - Lazy brokeredDebuggerServices, + Lazy brokeredDebuggerServices, IAsynchronousOperationListenerProvider listenerProvider) { _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; @@ -53,7 +53,7 @@ private class OnInitializedService : ILspService, IOnInitialized, IDisposable private readonly LspServices _lspServices; private readonly LspWorkspaceManager _lspWorkspaceManager; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly Lazy _brokeredDebuggerServices; + private readonly Lazy _brokeredDebuggerServices; private readonly System.Timers.Timer _timer; private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); private readonly IAsynchronousOperationListener _asyncListener; @@ -63,7 +63,7 @@ private class OnInitializedService : ILspService, IOnInitialized, IDisposable public OnInitializedService(LspServices lspServices, LspWorkspaceManager lspWorkspaceManager, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, - Lazy brokeredDebuggerServices, + Lazy brokeredDebuggerServices, IAsynchronousOperationListenerProvider listenerProvider) { _lspServices = lspServices; @@ -73,7 +73,7 @@ public OnInitializedService(LspServices lspServices, _timer = new System.Timers.Timer(); _timer.Interval = 500; _timer.Elapsed += Timer_Elapsed; - _asyncListener = listenerProvider.GetListener(nameof(VisualDiagnosticsBrokeredDebuggerServices)); + _asyncListener = listenerProvider.GetListener(nameof(VisualDiagnosticsServiceBroker)); } private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) @@ -115,7 +115,7 @@ private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync() return; } - IVisualDiagnosticsBrokeredDebuggerServices brokerService = _brokeredDebuggerServices.Value; + IVisualDiagnosticsServiceBroker brokerService = _brokeredDebuggerServices.Value; if (brokerService != null) { diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 0f90997e265b8..12a0ff0d54b35 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -1,23 +1,15 @@ -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo.ConnectionInfo() -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetHotReloadSessionNotificationServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadAgentManagerServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetManagedHotReloadServiceAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsBrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.HandleDiagnosticSessionStartAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.HandleDiagnosticSessionStopAsync(Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo info, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.InitializeAsync(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsLanguageService.RequestDataBridgeConnectionAsync(string! connectionId, System.Threading.CancellationToken token) -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ProcessInfo.ProcessInfo(System.Guid ProcessId, uint? LocalProcessId, string? Path) -> void -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsBrokeredDebuggerServices.VisualDiagnosticsBrokeredDebuggerServices(System.Lazy!>! serviceBroker) -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsServiceBroker +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsServiceBroker.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.VisualDiagnosticsServiceBroker(System.Lazy!>! serviceBroker) -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices, Microsoft.CodeAnalysis.Shared.TestHooks.IAsynchronousOperationListenerProvider! listenerProvider) -> void -~override Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.ConnectionInfo.ToString() -> string \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices, Microsoft.CodeAnalysis.Shared.TestHooks.IAsynchronousOperationListenerProvider! listenerProvider) -> void \ No newline at end of file From 22e778144db8602c5ee22aa091951f5a5c4c7de6 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 18 Mar 2024 16:59:24 -0700 Subject: [PATCH 25/40] Add VisualDiagnosticsServiceFactory to InternalAPI.Unshipped --- .../ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 12a0ff0d54b35..4c7a0209efcd2 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -12,4 +12,4 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices, Microsoft.CodeAnalysis.Shared.TestHooks.IAsynchronousOperationListenerProvider! listenerProvider) -> void \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices, Microsoft.CodeAnalysis.Shared.TestHooks.IAsynchronousOperationListenerProvider! listenerProvider) -> void \ No newline at end of file From b71fdff17292f52cc061ba3cef32a5f27be2a8b6 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Fri, 22 Mar 2024 13:31:30 -0700 Subject: [PATCH 26/40] Update architecture on getting the service broker --- .../BrokeredServices/ServiceBrokerFactory.cs | 42 ++++----- .../IVisualDiagnosticsServiceBroker.cs | 17 ---- .../VisualDiagnosticsServiceBroker.cs | 25 ++--- .../VisualDiagnosticsServiceFactory.cs | 92 +++++-------------- .../InternalAPI.Unshipped.txt | 8 +- ...is.ExternalAccess.VisualDiagnostics.csproj | 3 +- .../Core/IOnServiceBrokerInitialized.cs | 15 +++ ...soft.CodeAnalysis.Remote.Workspaces.csproj | 1 + 8 files changed, 75 insertions(+), 128 deletions(-) delete mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs create mode 100644 src/Workspaces/Remote/Core/IOnServiceBrokerInitialized.cs diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs index 08bc94d070588..0b0a6ca22791a 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Immutable; using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.BrokeredServices; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Composition; @@ -26,18 +28,20 @@ namespace Microsoft.CodeAnalysis.LanguageServer.BrokeredServices; [Export] internal class ServiceBrokerFactory { - private readonly TaskCompletionSource _container; + private BrokeredServiceContainer? _container; private readonly ExportProvider _exportProvider; private Task _bridgeCompletionTask; private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + private readonly ImmutableArray _onServiceBrokerInitialized; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public ServiceBrokerFactory(ExportProvider exportProvider) + public ServiceBrokerFactory([ImportMany] IEnumerable onServiceBrokerInitialized, + ExportProvider exportProvider) { _exportProvider = exportProvider; _bridgeCompletionTask = Task.CompletedTask; - _container = new TaskCompletionSource(); + _onServiceBrokerInitialized = onServiceBrokerInitialized.ToImmutableArray(); } /// @@ -49,19 +53,12 @@ public ServiceBrokerFactory(ExportProvider exportProvider) /// /// Returns a full-access service broker, but will return null if we haven't yet connected to the Dev Kit broker. /// - public IServiceBroker? TryGetFullAccessServiceBroker() => _container.Task.IsCompletedSuccessfully ? _container.Task.Result?.GetFullAccessServiceBroker() : null; - - /// - /// Returns a full-access service broker container, that consuming code can await on until we connected to the Dev Kit broker - /// - [Export(typeof(SVsBrokeredServiceContainer))] - public Task BrokeredServiceContainerAsync => this.GetRequiredServiceBrokerContainerAsync(); + public IServiceBroker? TryGetFullAccessServiceBroker() => _container?.GetFullAccessServiceBroker(); public BrokeredServiceContainer GetRequiredServiceBrokerContainer() { - Contract.ThrowIfFalse(_container.Task.IsCompletedSuccessfully); - Contract.ThrowIfNull(_container.Task.Result); - return _container.Task.Result; + Contract.ThrowIfNull(_container); + return _container; } /// @@ -69,10 +66,14 @@ public BrokeredServiceContainer GetRequiredServiceBrokerContainer() /// public async Task CreateAsync() { - Contract.ThrowIfFalse(!_container.Task.IsCompleted, "We should only create one container."); + Contract.ThrowIfFalse(_container == null, "We should only create one container."); + + _container = await BrokeredServiceContainer.CreateAsync(_exportProvider, _cancellationTokenSource.Token); - var container = await BrokeredServiceContainer.CreateAsync(_exportProvider, _cancellationTokenSource.Token); - _container.TrySetResult(container); + foreach (var onInitialized in _onServiceBrokerInitialized) + { + onInitialized.OnServiceBrokerInitialized(_container.GetFullAccessServiceBroker()); + } } public async Task CreateAndConnectAsync(string brokeredServicePipeName) @@ -80,7 +81,7 @@ public async Task CreateAndConnectAsync(string brokeredServicePipeName) await CreateAsync(); var bridgeProvider = _exportProvider.GetExportedValue(); - _bridgeCompletionTask = bridgeProvider.SetupBrokeredServicesBridgeAsync(brokeredServicePipeName, _container.Task.Result!, _cancellationTokenSource.Token); + _bridgeCompletionTask = bridgeProvider.SetupBrokeredServicesBridgeAsync(brokeredServicePipeName, _container!, _cancellationTokenSource.Token); } public Task ShutdownAndWaitForCompletionAsync() @@ -91,12 +92,5 @@ public Task ShutdownAndWaitForCompletionAsync() // completed task set in the constructor, so the waiter no-ops. return _bridgeCompletionTask; } - - private async Task GetRequiredServiceBrokerContainerAsync() - { - // Caller of this method are expected to wait until the container is set by CreateAsync - var brokeredServiceContainer = await _container.Task.ConfigureAwait(false); - return brokeredServiceContainer; - } } #pragma warning restore RS0030 // Do not used banned APIs diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs deleted file mode 100644 index 37a29d31e00e1..0000000000000 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsServiceBroker.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Microsoft.ServiceHub.Framework; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts -{ - /// - /// Facade interface for getting broker service successfully through MEF - /// - internal interface IVisualDiagnosticsServiceBroker - { - Task GetServiceBrokerAsync(); - } -} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs index 72364e437d19d..e4a57b2768109 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs @@ -4,37 +4,32 @@ using System; using System.ComponentModel.Composition; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; +using Microsoft.CodeAnalysis.BrokeredServices; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Composition; -using Microsoft.VisualStudio.Shell.ServiceBroker; namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal { /// - /// This is a simple wrapper to succeed at getting the broker service using System.ComponentModel.Composition inside an LSP service OnInitialized factory + /// This is a simple wrapper to export IOnServiceBrokerInitialized to the ServiceBrokerFactory and delegate back to + /// to the LSP services once the broker service is initialized. /// - [Export(typeof(IVisualDiagnosticsServiceBroker))] - internal sealed class VisualDiagnosticsServiceBroker : IVisualDiagnosticsServiceBroker + [Export] + [Export(typeof(IOnServiceBrokerInitialized))] + internal sealed class VisualDiagnosticsServiceBroker : IOnServiceBrokerInitialized { - private readonly Lazy> _container; + public IOnServiceBrokerInitialized? NotifyServiceBrokerInitialized { get; set; } [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualDiagnosticsServiceBroker( - [Import(typeof(SVsBrokeredServiceContainer))] - Lazy> serviceBroker) + public VisualDiagnosticsServiceBroker() { - _container = serviceBroker; } - public async Task GetServiceBrokerAsync() + public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) { - // Waiting on the container to be created - await _container.Value.ConfigureAwait(false); - return _container.Value.Result.GetFullAccessServiceBroker(); + NotifyServiceBrokerInitialized?.OnServiceBrokerInitialized(serviceBroker); } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 4b804c68bbb2a..651587d99b584 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.BrokeredServices; using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal; using Microsoft.CodeAnalysis.Host.Mef; @@ -27,118 +28,73 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory { private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly Lazy _brokeredDebuggerServices; - private readonly IAsynchronousOperationListenerProvider _listenerProvider; + private readonly VisualDiagnosticsServiceBroker _brokeredDebuggerServices; [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [ImportingConstructor] public VisualDiagnosticsServiceFactory( LspWorkspaceRegistrationService lspWorkspaceRegistrationService, - Lazy brokeredDebuggerServices, - IAsynchronousOperationListenerProvider listenerProvider) + VisualDiagnosticsServiceBroker brokeredDebuggerServices) { _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; _brokeredDebuggerServices = brokeredDebuggerServices; - _listenerProvider = listenerProvider; } public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) { - var lspWorkspaceManager = lspServices.GetRequiredService(); - return new OnInitializedService(lspServices, lspWorkspaceManager, _lspWorkspaceRegistrationService, _brokeredDebuggerServices, _listenerProvider); + return new OnInitializedService(_lspWorkspaceRegistrationService, _brokeredDebuggerServices); } - private class OnInitializedService : ILspService, IOnInitialized, IDisposable + private class OnInitializedService : ILspService, IOnInitialized, IOnServiceBrokerInitialized, IDisposable { - private readonly LspServices _lspServices; - private readonly LspWorkspaceManager _lspWorkspaceManager; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly Lazy _brokeredDebuggerServices; - private readonly System.Timers.Timer _timer; - private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1); - private readonly IAsynchronousOperationListener _asyncListener; + private readonly VisualDiagnosticsServiceBroker _brokeredDebuggerServices; private IVisualDiagnosticsLanguageService? _visualDiagnosticsLanguageService; private CancellationToken _cancellationToken; + private static readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); - public OnInitializedService(LspServices lspServices, - LspWorkspaceManager lspWorkspaceManager, - LspWorkspaceRegistrationService lspWorkspaceRegistrationService, - Lazy brokeredDebuggerServices, - IAsynchronousOperationListenerProvider listenerProvider) + public OnInitializedService(LspWorkspaceRegistrationService lspWorkspaceRegistrationService, VisualDiagnosticsServiceBroker brokeredDebuggerServices) { - _lspServices = lspServices; - _lspWorkspaceManager = lspWorkspaceManager; _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; _brokeredDebuggerServices = brokeredDebuggerServices; - _timer = new System.Timers.Timer(); - _timer.Interval = 500; - _timer.Elapsed += Timer_Elapsed; - _asyncListener = listenerProvider.GetListener(nameof(VisualDiagnosticsServiceBroker)); - } - private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - _timer.Stop(); - var token = _asyncListener.BeginAsyncOperation(nameof(OnInitializedService) + ".Timer_Elapsed"); - _ = OnTimerElapsedAsync().CompletesAsyncOperation(token); + _brokeredDebuggerServices.NotifyServiceBrokerInitialized = this; } public void Dispose() { (_visualDiagnosticsLanguageService as IDisposable)?.Dispose(); - _timer?.Dispose(); } public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { _cancellationToken = cancellationToken; - // TODO dabarbe: Calling ServiceBrokerFactory.GetRequiredServiceBrokerContainerAsync.ConfigureAwait(false); here prevents - // ServiceBrokerConnectHandler from being initialized. Not sure why? There's something in the synchronization context that - // prevents TaskCompletionSource tasks to run properly during the LSP initialization. Solution is to getting out of OnInitializedAsync and calling - // _brokeredDebuggerServices.Value.GetServiceBrokerAsync().ConfigureAwait(false) on the timer dispatcher, which is a separate synchronization context. This - // allows GetServiceBrokerAsync() to await until ServiceBrokerFactory.CreateAsync sets the container, and allowing the task completion source to resume - _timer.Start(); + _taskCompletionSource.SetResult(true); return Task.CompletedTask; } - private async Task OnTimerElapsedAsync() + public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) { - await OnInitializeVisualDiagnosticsLanguageServiceAsync().ConfigureAwait(false); + Task.Run(async () => await OnInitializeVisualDiagnosticsLanguageServiceAsync(serviceBroker).ConfigureAwait(false)); } - private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync() + private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync(IServiceBroker serviceBroker) { - using (await _mutex.DisposableWaitAsync().ConfigureAwait(false)) + // Make sure we're initialized. + bool initialized = await _taskCompletionSource.Task.ConfigureAwait(false); + + if (initialized && serviceBroker != null) { - if (_visualDiagnosticsLanguageService != null) + // initialize VisualDiagnosticsLanguageService + Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + if (workspace != null) { - return; - } - - IVisualDiagnosticsServiceBroker brokerService = _brokeredDebuggerServices.Value; + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); - if (brokerService != null) - { - // The broker service may be not available right await. That's because the broker service gets initialized - // when the C# DevKit is getting initialized in parallel. GetServiceBrokerAsync() will await until - // the container gets created. Once created, this task will resume. In case where C# Dev kit is not - // enabled, the service broker container will never be created and this task will never return, thus preventing - // us from creating the IVisualDiagnosticsLanguageService - IServiceBroker? serviceBroker = await brokerService.GetServiceBrokerAsync().ConfigureAwait(false); - if (serviceBroker != null) + if (visualDiagnosticsLanguageService != null) { - // initialize VisualDiagnosticsLanguageService - Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); - if (workspace != null) - { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); - - if (visualDiagnosticsLanguageService != null) - { - await visualDiagnosticsLanguageService.InitializeAsync(serviceBroker, _cancellationToken).ConfigureAwait(false); - _visualDiagnosticsLanguageService = visualDiagnosticsLanguageService; - } - } + await visualDiagnosticsLanguageService.InitializeAsync(serviceBroker, _cancellationToken).ConfigureAwait(false); + _visualDiagnosticsLanguageService = visualDiagnosticsLanguageService; } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index 4c7a0209efcd2..e96fb291198a6 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -6,10 +6,12 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnos Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsServiceBroker Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts.IVisualDiagnosticsServiceBroker.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.GetServiceBrokerAsync() -> System.Threading.Tasks.Task! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.VisualDiagnosticsServiceBroker(System.Lazy!>! serviceBroker) -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.NotifyServiceBrokerInitialized.get -> Microsoft.CodeAnalysis.BrokeredServices.IOnServiceBrokerInitialized? +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.NotifyServiceBrokerInitialized.set -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.OnServiceBrokerInitialized(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker.VisualDiagnosticsServiceBroker() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, System.Lazy! brokeredDebuggerServices, Microsoft.CodeAnalysis.Shared.TestHooks.IAsynchronousOperationListenerProvider! listenerProvider) -> void \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker! brokeredDebuggerServices) -> void \ No newline at end of file diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index b55110703caa2..e37c75e6745e9 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -18,7 +18,7 @@ - + @@ -34,6 +34,7 @@ + diff --git a/src/Workspaces/Remote/Core/IOnServiceBrokerInitialized.cs b/src/Workspaces/Remote/Core/IOnServiceBrokerInitialized.cs new file mode 100644 index 0000000000000..b47826b50f630 --- /dev/null +++ b/src/Workspaces/Remote/Core/IOnServiceBrokerInitialized.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.ServiceHub.Framework; + +namespace Microsoft.CodeAnalysis.BrokeredServices; + +/// +/// Allow services to export IOnServiceBrokerInitialized and getting called back when service broker is initialized +/// +internal interface IOnServiceBrokerInitialized +{ + void OnServiceBrokerInitialized(IServiceBroker serviceBroker); +} diff --git a/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj b/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj index 2a2b29384f61b..05f63516078fa 100644 --- a/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj +++ b/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj @@ -63,6 +63,7 @@ + From 3ac0c7a5ea07f0d980231a7ddd37772124abcece Mon Sep 17 00:00:00 2001 From: Bret Johnson Date: Mon, 25 Mar 2024 12:41:18 -0400 Subject: [PATCH 27/40] Update protocol to v3 for MauiLaunchCustomizer brokered service Per guidance from Andrew Arnott, we should the new protocol version, v3, for new brokered services, so update MauiLaunchCustomizerService to do that. This change goes along with matching changes to the service descriptor in https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_git/VS/pullrequest/535594 and https://devdiv.visualstudio.com/DevDiv/_git/vscode-maui/pullrequest/519152. --- .../Remote/Core/BrokeredServiceDescriptors.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs index 3b26bcf0b55ff..ec8e5ac585bf0 100644 --- a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs +++ b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs @@ -4,6 +4,7 @@ using System; using Microsoft.ServiceHub.Framework; +using Nerdbank.Streams; using StreamJsonRpc; using static Microsoft.ServiceHub.Framework.ServiceJsonRpcDescriptor; @@ -73,7 +74,7 @@ protected override JsonRpcConnection CreateConnection(JsonRpc jsonRpc) public static readonly ServiceRpcDescriptor HotReloadLoggerService = CreateDebuggerServiceDescriptor("HotReloadLogger", new Version(0, 1)); public static readonly ServiceRpcDescriptor HotReloadSessionNotificationService = CreateDebuggerServiceDescriptor("HotReloadSessionNotificationService", new Version(0, 1)); public static readonly ServiceRpcDescriptor ManagedHotReloadAgentManagerService = CreateDebuggerServiceDescriptor("ManagedHotReloadAgentManagerService", new Version(0, 1)); - public static readonly ServiceRpcDescriptor MauiLaunchCustomizerServiceDescriptor = CreateMauiClientServiceDescriptor("MauiLaunchCustomizerService", new Version(0, 1)); + public static readonly ServiceRpcDescriptor MauiLaunchCustomizerServiceDescriptor = CreateMauiServiceDescriptor("MauiLaunchCustomizerService", new Version(0, 1)); public static ServiceMoniker CreateMoniker(string namespaceName, string componentName, string serviceName, Version? version) => new(namespaceName + "." + componentName + "." + serviceName, version); @@ -98,10 +99,12 @@ public static ServiceJsonRpcDescriptor CreateDebuggerServiceDescriptor(string se => CreateDescriptor(CreateMoniker(VisualStudioComponentNamespace, DebuggerComponentName, serviceName, version)); /// - /// Descriptor for services proferred by the MAUI client extension (implemented in TypeScript). + /// Descriptor for services proferred by the MAUI extension (implemented in TypeScript). /// - public static ServiceJsonRpcDescriptor CreateMauiClientServiceDescriptor(string serviceName, Version? version) - => new ClientServiceDescriptor(CreateMoniker(VisualStudioComponentNamespace, "Maui", serviceName, version), clientInterface: null) + public static ServiceJsonRpcDescriptor CreateMauiServiceDescriptor(string serviceName, Version? version) + => new ServiceJsonRpcDescriptor(CreateMoniker(VisualStudioComponentNamespace, "Maui", serviceName, version), clientInterface: null, + Formatters.MessagePack, MessageDelimiters.BigEndianInt32LengthHeader, + new MultiplexingStream.Options { ProtocolMajorVersion = 3 }) .WithExceptionStrategy(ExceptionProcessing.ISerializable); private static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker moniker) From e47cfc41b7104b9ca2ac6fd63f5b582ad65dcf41 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 25 Mar 2024 12:52:29 -0700 Subject: [PATCH 28/40] Removal of VisualDiagnosticsServiceBroker --- .../VisualDiagnosticsServiceBroker.cs | 35 ------------ .../VisualDiagnosticsServiceFactory.cs | 55 +++++++------------ .../InternalAPI.Unshipped.txt | 3 +- 3 files changed, 23 insertions(+), 70 deletions(-) delete mode 100644 src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs deleted file mode 100644 index e4a57b2768109..0000000000000 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceBroker.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.ComponentModel.Composition; -using Microsoft.CodeAnalysis.BrokeredServices; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Composition; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal -{ - /// - /// This is a simple wrapper to export IOnServiceBrokerInitialized to the ServiceBrokerFactory and delegate back to - /// to the LSP services once the broker service is initialized. - /// - [Export] - [Export(typeof(IOnServiceBrokerInitialized))] - internal sealed class VisualDiagnosticsServiceBroker : IOnServiceBrokerInitialized - { - public IOnServiceBrokerInitialized? NotifyServiceBrokerInitialized { get; set; } - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualDiagnosticsServiceBroker() - { - } - - public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) - { - NotifyServiceBrokerInitialized?.OnServiceBrokerInitialized(serviceBroker); - } - } -} diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 651587d99b584..e37c131d35ca5 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -9,11 +9,9 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.BrokeredServices; using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Contracts; -using Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.ServiceHub.Framework; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; @@ -24,41 +22,36 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics; /// LSP Service responsible for loading IVisualDiagnosticsLanguageService workspace service and delegate the broker service to the workspace service, /// and handling MAUI XAML/C#/CSS/Razor Hot Reload support /// +[Export(typeof(IOnServiceBrokerInitialized))] [ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] -internal sealed class VisualDiagnosticsServiceFactory : ILspServiceFactory +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +[method: ImportingConstructor] +internal sealed class VisualDiagnosticsServiceFactory( + LspWorkspaceRegistrationService lspWorkspaceRegistrationService) : ILspServiceFactory, IOnServiceBrokerInitialized { - private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly VisualDiagnosticsServiceBroker _brokeredDebuggerServices; + private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; + private readonly Lazy _OnInitializedService = new Lazy(() => new OnInitializedService(lspWorkspaceRegistrationService)); - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - [ImportingConstructor] - public VisualDiagnosticsServiceFactory( - LspWorkspaceRegistrationService lspWorkspaceRegistrationService, - VisualDiagnosticsServiceBroker brokeredDebuggerServices) + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) { - _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; - _brokeredDebuggerServices = brokeredDebuggerServices; + return _OnInitializedService.Value; } - public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) { - return new OnInitializedService(_lspWorkspaceRegistrationService, _brokeredDebuggerServices); + _OnInitializedService.Value?.OnServiceBrokerInitialized(serviceBroker); } private class OnInitializedService : ILspService, IOnInitialized, IOnServiceBrokerInitialized, IDisposable { private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - private readonly VisualDiagnosticsServiceBroker _brokeredDebuggerServices; private IVisualDiagnosticsLanguageService? _visualDiagnosticsLanguageService; private CancellationToken _cancellationToken; private static readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); - public OnInitializedService(LspWorkspaceRegistrationService lspWorkspaceRegistrationService, VisualDiagnosticsServiceBroker brokeredDebuggerServices) + public OnInitializedService(LspWorkspaceRegistrationService lspWorkspaceRegistrationService) { _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; - _brokeredDebuggerServices = brokeredDebuggerServices; - - _brokeredDebuggerServices.NotifyServiceBrokerInitialized = this; } public void Dispose() @@ -75,27 +68,21 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) { - Task.Run(async () => await OnInitializeVisualDiagnosticsLanguageServiceAsync(serviceBroker).ConfigureAwait(false)); + _taskCompletionSource.Task.ContinueWith((initialized) => OnInitializeVisualDiagnosticsLanguageServiceAsync(serviceBroker), TaskScheduler.Default); } private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync(IServiceBroker serviceBroker) { - // Make sure we're initialized. - bool initialized = await _taskCompletionSource.Task.ConfigureAwait(false); - - if (initialized && serviceBroker != null) + // initialize VisualDiagnosticsLanguageService + Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + if (workspace != null) { - // initialize VisualDiagnosticsLanguageService - Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); - if (workspace != null) - { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); - if (visualDiagnosticsLanguageService != null) - { - await visualDiagnosticsLanguageService.InitializeAsync(serviceBroker, _cancellationToken).ConfigureAwait(false); - _visualDiagnosticsLanguageService = visualDiagnosticsLanguageService; - } + if (visualDiagnosticsLanguageService != null) + { + await visualDiagnosticsLanguageService.InitializeAsync(serviceBroker, _cancellationToken).ConfigureAwait(false); + _visualDiagnosticsLanguageService = visualDiagnosticsLanguageService; } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt index e96fb291198a6..504106533fe6b 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/VisualDiagnostics/InternalAPI.Unshipped.txt @@ -14,4 +14,5 @@ Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.RunningProcessEntry.RunningProcessEntry() -> void Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService, Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.Internal.VisualDiagnosticsServiceBroker! brokeredDebuggerServices) -> void \ No newline at end of file +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.OnServiceBrokerInitialized(Microsoft.ServiceHub.Framework.IServiceBroker! serviceBroker) -> void +Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.VisualDiagnosticsServiceFactory.VisualDiagnosticsServiceFactory(Microsoft.CodeAnalysis.LanguageServer.LspWorkspaceRegistrationService! lspWorkspaceRegistrationService) -> void \ No newline at end of file From 5eacd8052298cdf8da6244da450fca0f50409894 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 25 Mar 2024 13:32:25 -0700 Subject: [PATCH 29/40] add Contract.ThrowIfFalse(workspace != null) as Host Workspace is always guaranteed --- .../Internal/VisualDiagnosticsServiceFactory.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index e37c131d35ca5..a7b648d1e5567 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -75,15 +75,14 @@ private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync(IServiceBro { // initialize VisualDiagnosticsLanguageService Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); - if (workspace != null) - { - IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); + Contract.ThrowIfFalse(workspace != null, "We should always have a host workspace."); + + IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); - if (visualDiagnosticsLanguageService != null) - { - await visualDiagnosticsLanguageService.InitializeAsync(serviceBroker, _cancellationToken).ConfigureAwait(false); - _visualDiagnosticsLanguageService = visualDiagnosticsLanguageService; - } + if (visualDiagnosticsLanguageService != null) + { + await visualDiagnosticsLanguageService.InitializeAsync(serviceBroker, _cancellationToken).ConfigureAwait(false); + _visualDiagnosticsLanguageService = visualDiagnosticsLanguageService; } } } From 32ee44593a6d623d420dbbae22e1c77f078bd89a Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 25 Mar 2024 14:47:53 -0700 Subject: [PATCH 30/40] Update src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs Co-authored-by: David Barbet --- .../Internal/VisualDiagnosticsServiceFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index a7b648d1e5567..9910b29159386 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -39,7 +39,7 @@ public ILspService CreateILspService(LspServices lspServices, WellKnownLspServer public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) { - _OnInitializedService.Value?.OnServiceBrokerInitialized(serviceBroker); + _OnInitializedService.Value.OnServiceBrokerInitialized(serviceBroker); } private class OnInitializedService : ILspService, IOnInitialized, IOnServiceBrokerInitialized, IDisposable From 6f88ecf2e03dd7f5fc3d82bea14060b1781884aa Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 25 Mar 2024 17:36:41 -0700 Subject: [PATCH 31/40] Remove extra refererence no longer needed --- ...t.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index e37c75e6745e9..5ae4cc695ecd8 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -20,14 +20,6 @@ - - - - - - - - From 1f6f8fc0368696799da95a7b950ce35085b0a0af Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 25 Mar 2024 17:49:35 -0700 Subject: [PATCH 32/40] Fixing a VS coding guideline slip up --- .../Internal/VisualDiagnosticsServiceFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 9910b29159386..5023b83e1e39e 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -74,7 +74,7 @@ public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync(IServiceBroker serviceBroker) { // initialize VisualDiagnosticsLanguageService - Workspace workspace = this._lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + Workspace workspace = _lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); Contract.ThrowIfFalse(workspace != null, "We should always have a host workspace."); IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); From ce7b628282f1c5b34fe84f23203fd49d9157f90d Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 25 Mar 2024 22:21:40 -0700 Subject: [PATCH 33/40] Add Microsoft.VisualStudio.Debugger.Contracts.dll as a reference in order for IVisualDiagnosticsLanguageService to load --- ...soft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 5ae4cc695ecd8..419610a7ed6e1 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -20,6 +20,11 @@ + + + + + From aaa4e633400e02cace2bfda34f7f6ec2da1f2f5e Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Mon, 25 Mar 2024 22:21:40 -0700 Subject: [PATCH 34/40] Add Microsoft.VisualStudio.Debugger.Contracts.dll as a reference in order for IVisualDiagnosticsLanguageService to load --- ...soft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 5ae4cc695ecd8..4571600efbb03 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -20,6 +20,11 @@ + + + + + From 10511e4dd715613d63ddd5c8aff1eda016e26622 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Tue, 26 Mar 2024 12:02:13 -0700 Subject: [PATCH 35/40] Remove Microsoft.VisualStudio.Debugger.Contract because it's close source --- ...soft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 4571600efbb03..5ae4cc695ecd8 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -20,11 +20,6 @@ - - - - - From 0dbc2b98405e5732405438aa8139fd0973df9b99 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Tue, 26 Mar 2024 13:15:23 -0700 Subject: [PATCH 36/40] remove internalvisibleto --- ...t.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index 5ae4cc695ecd8..b353a7f1dc51c 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -14,13 +14,6 @@ https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/Xaml/Diagnostics/Source/CodeAnalysisDiagnostics - - - - - - - @@ -28,7 +21,6 @@ - From db1e0283c7e05a9ac98dd3755cbe13e3cabdf018 Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Tue, 26 Mar 2024 15:08:42 -0700 Subject: [PATCH 37/40] changing to TrySetResult to pass tests --- .../Internal/VisualDiagnosticsServiceFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 5023b83e1e39e..1467ed344888c 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -62,7 +62,7 @@ public void Dispose() public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { _cancellationToken = cancellationToken; - _taskCompletionSource.SetResult(true); + _taskCompletionSource.TrySetResult(true); return Task.CompletedTask; } From 2120cf9f414274bbcf28e2aa152569806f7aa31e Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Wed, 27 Mar 2024 22:14:46 -0700 Subject: [PATCH 38/40] Update comment --- ...crosoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index b353a7f1dc51c..cec05f024c1ee 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -10,7 +10,7 @@ true Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics - A supporting package for Visual Studio CodeAnalysisDiagnostics: + A supporting package for Visual Studio Microsoft.VisualStudio.DesignTools.CodeAnalysis.Diagnostics: https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/Xaml/Diagnostics/Source/CodeAnalysisDiagnostics From a9c9937d773ae771ccc534bf4404c53e54899a5c Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Thu, 28 Mar 2024 22:36:51 -0700 Subject: [PATCH 39/40] make IVisualDiagnosticsLanguageService internal to foce internalvisible to components consuming it --- .../BrokeredServices/ServiceBrokerFactory.cs | 8 +++++++- .../Contracts/IVisualDiagnosticsLanguageService.cs | 2 +- .../Internal/VisualDiagnosticsServiceFactory.cs | 2 +- ...t.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 5 +++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs index 0b0a6ca22791a..8ad3f78c6dac2 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs @@ -72,7 +72,13 @@ public async Task CreateAsync() foreach (var onInitialized in _onServiceBrokerInitialized) { - onInitialized.OnServiceBrokerInitialized(_container.GetFullAccessServiceBroker()); + try + { + onInitialized.OnServiceBrokerInitialized(_container.GetFullAccessServiceBroker()); + } + catch (Exception) + { + } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index 73225b06135c4..fa0bfc3b929b4 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -21,6 +21,6 @@ internal interface IVisualDiagnosticsLanguageService : IWorkspaceService, IDispo /// Service broker /// Cancellation token /// - public Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); + Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 1467ed344888c..ce9a367059a7d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -74,7 +74,7 @@ public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync(IServiceBroker serviceBroker) { // initialize VisualDiagnosticsLanguageService - Workspace workspace = _lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + Workspace workspace = _lspWorkspaceRegistrationService.GetAllRegistrations().First(w => w.Kind == WorkspaceKind.Host); Contract.ThrowIfFalse(workspace != null, "We should always have a host workspace."); IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index cec05f024c1ee..065b77ab5bb27 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -14,6 +14,11 @@ https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/Xaml/Diagnostics/Source/CodeAnalysisDiagnostics + + + + + From 51df9ab8c315f78e5dab738d2c6a65d3efcedadf Mon Sep 17 00:00:00 2001 From: Charles Bissonnette Date: Thu, 28 Mar 2024 22:36:51 -0700 Subject: [PATCH 40/40] make IVisualDiagnosticsLanguageService internal to foce internalvisible to components consuming it --- .../BrokeredServices/ServiceBrokerFactory.cs | 8 +++++++- .../Contracts/IVisualDiagnosticsLanguageService.cs | 2 +- .../Internal/VisualDiagnosticsServiceFactory.cs | 2 +- ...t.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj | 5 +++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs index 0b0a6ca22791a..8ad3f78c6dac2 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/ServiceBrokerFactory.cs @@ -72,7 +72,13 @@ public async Task CreateAsync() foreach (var onInitialized in _onServiceBrokerInitialized) { - onInitialized.OnServiceBrokerInitialized(_container.GetFullAccessServiceBroker()); + try + { + onInitialized.OnServiceBrokerInitialized(_container.GetFullAccessServiceBroker()); + } + catch (Exception) + { + } } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs index 73225b06135c4..fa0bfc3b929b4 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Contracts/IVisualDiagnosticsLanguageService.cs @@ -21,6 +21,6 @@ internal interface IVisualDiagnosticsLanguageService : IWorkspaceService, IDispo /// Service broker /// Cancellation token /// - public Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); + Task InitializeAsync(IServiceBroker serviceBroker, CancellationToken token); } } diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs index 1467ed344888c..ce9a367059a7d 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Internal/VisualDiagnosticsServiceFactory.cs @@ -74,7 +74,7 @@ public void OnServiceBrokerInitialized(IServiceBroker serviceBroker) private async Task OnInitializeVisualDiagnosticsLanguageServiceAsync(IServiceBroker serviceBroker) { // initialize VisualDiagnosticsLanguageService - Workspace workspace = _lspWorkspaceRegistrationService.GetAllRegistrations().Where(w => w.Kind == WorkspaceKind.Host).FirstOrDefault(); + Workspace workspace = _lspWorkspaceRegistrationService.GetAllRegistrations().First(w => w.Kind == WorkspaceKind.Host); Contract.ThrowIfFalse(workspace != null, "We should always have a host workspace."); IVisualDiagnosticsLanguageService? visualDiagnosticsLanguageService = workspace.Services.GetService(); diff --git a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj index cec05f024c1ee..ada2581f782b5 100644 --- a/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj +++ b/src/Tools/ExternalAccess/VisualDiagnostics/Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics.csproj @@ -14,6 +14,11 @@ https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/Xaml/Diagnostics/Source/CodeAnalysisDiagnostics + + + + +