File: Remote\InProcRemoteHostClientProvider.cs
Web Access
Project: src\src\Workspaces\CoreTestUtilities\Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj (Microsoft.CodeAnalysis.Workspaces.Test.Utilities)
// 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.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests.Remote;
using Microsoft.VisualStudio.Threading;
using Roslyn.Test.Utilities;
 
namespace Microsoft.CodeAnalysis.Remote.Testing
{
#pragma warning disable CA1416 // Validate platform compatibility
    internal sealed class InProcRemoteHostClientProvider : IRemoteHostClientProvider, IDisposable
    {
        [ExportWorkspaceServiceFactory(typeof(IRemoteHostClientProvider), ServiceLayer.Test), Shared, PartNotDiscoverable]
        internal sealed class Factory : IWorkspaceServiceFactory
        {
            private readonly RemoteServiceCallbackDispatcherRegistry _callbackDispatchers;
 
            [ImportingConstructor]
            [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
            public Factory([ImportMany] IEnumerable<Lazy<IRemoteServiceCallbackDispatcher, RemoteServiceCallbackDispatcherRegistry.ExportMetadata>> callbackDispatchers)
                => _callbackDispatchers = new RemoteServiceCallbackDispatcherRegistry(callbackDispatchers);
 
            public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
                => new InProcRemoteHostClientProvider(workspaceServices.SolutionServices, _callbackDispatchers);
        }
 
        private sealed class WorkspaceManager : RemoteWorkspaceManager
        {
            public WorkspaceManager(
                Func<RemoteWorkspace, SolutionAssetCache> createAssetStorage,
                ConcurrentDictionary<Guid, TestGeneratorReference> sharedTestGeneratorReferences,
                Type[]? additionalRemoteParts,
                Type[]? excludedRemoteParts)
                : base(createAssetStorage, CreateRemoteWorkspace(sharedTestGeneratorReferences, additionalRemoteParts, excludedRemoteParts))
            {
            }
        }
 
        private static RemoteWorkspace CreateRemoteWorkspace(
            ConcurrentDictionary<Guid, TestGeneratorReference> sharedTestGeneratorReferences,
            Type[]? additionalRemoteParts,
            Type[]? excludedRemoteParts)
        {
            var hostServices = FeaturesTestCompositions.RemoteHost.AddParts(additionalRemoteParts).AddExcludedPartTypes(excludedRemoteParts).GetHostServices();
 
            // We want to allow references to source generators to be shared between the "in proc" and "remote" workspaces and
            // MEF compositions, so tell the serializer service to use the same map for this "remote" workspace as the in-proc one.
            ((IMefHostExportProvider)hostServices).GetExportedValue<TestSerializerService.Factory>().SharedTestGeneratorReferences = sharedTestGeneratorReferences;
            return new RemoteWorkspace(hostServices);
        }
 
        private readonly SolutionServices _services;
        private readonly Lazy<WorkspaceManager> _lazyManager;
        private readonly Lazy<RemoteHostClient> _lazyClient;
        private readonly TaskCompletionSource<bool> _clientCreationSource = new();
 
        public Type[]? AdditionalRemoteParts { get; set; }
        public Type[]? ExcludedRemoteParts { get; set; }
        public TraceListener? TraceListener { get; set; }
 
        public InProcRemoteHostClientProvider(SolutionServices services, RemoteServiceCallbackDispatcherRegistry callbackDispatchers)
        {
            _services = services;
 
            var testSerializerServiceFactory = services.ExportProvider.GetExportedValue<TestSerializerService.Factory>();
 
            _lazyManager = new Lazy<WorkspaceManager>(
                () => new WorkspaceManager(
                    _ => new SolutionAssetCache(),
                    testSerializerServiceFactory.SharedTestGeneratorReferences,
                    AdditionalRemoteParts,
                    ExcludedRemoteParts));
            _lazyClient = new Lazy<RemoteHostClient>(
                () =>
                {
                    try
                    {
                        return InProcRemoteHostClient.Create(
                            _services,
                            callbackDispatchers,
                            TraceListener,
                            new RemoteHostTestData(_lazyManager.Value, isInProc: true));
                    }
                    finally
                    {
                        _clientCreationSource.SetResult(true);
                    }
                });
        }
 
        public void Dispose()
        {
            // Dispose the remote workspace when the owning host workspace is disposed
            if (_lazyManager.IsValueCreated)
            {
                var manager = _lazyManager.Value;
                manager.GetWorkspace().Dispose();
            }
        }
 
        public Task<RemoteHostClient?> TryGetRemoteHostClientAsync(CancellationToken cancellationToken)
            => Task.FromResult<RemoteHostClient?>(_lazyClient.Value);
 
        public Task WaitForClientCreationAsync(CancellationToken cancellationToken)
            => _clientCreationSource.Task.WithCancellation(cancellationToken);
    }
#pragma warning restore CA1416 // Validate platform compatibility
}