public override async Task <bool> IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken) { using (RoslynLogger.LogBlock(FunctionId.SnapshotService_IsExperimentEnabledAsync, experimentName, cancellationToken)) { return(await _owner.RunServiceAsync(() => { return _owner.InvokeAsync <bool>(WellKnownServiceHubServices.AssetService_IsExperimentEnabledAsync, new object[] { experimentName }, cancellationToken); }, cancellationToken).ConfigureAwait(false)); } }
private static void SetRoslynLogger <T>(List <string> loggerTypes, Func <T> creator) where T : ILogger { if (loggerTypes.Contains(typeof(T).Name)) { RoslynLogger.SetLogger(AggregateLogger.AddOrReplace(creator(), RoslynLogger.GetLogger(), l => l is T)); } else { RoslynLogger.SetLogger(AggregateLogger.Remove(RoslynLogger.GetLogger(), l => l is T)); } }
public Task SynchronizePrimaryWorkspaceAsync(PinnedSolutionInfo solutionInfo, Checksum checksum, int workspaceVersion, CancellationToken cancellationToken) { return(RunServiceAsync(async() => { using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizePrimaryWorkspaceAsync, Checksum.GetChecksumLogInfo, checksum, cancellationToken)) { var solutionService = CreateSolutionService(solutionInfo); await solutionService.UpdatePrimaryWorkspaceAsync(checksum, workspaceVersion, cancellationToken).ConfigureAwait(false); } }, cancellationToken)); }
public Task SynchronizePrimaryWorkspaceAsync(Checksum checksum, CancellationToken cancellationToken) { return(RunServiceAsync(async token => { using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizePrimaryWorkspaceAsync, Checksum.GetChecksumLogInfo, checksum, token)) { var solutionController = (ISolutionController)RoslynServices.SolutionService; await solutionController.UpdatePrimaryWorkspaceAsync(checksum, token).ConfigureAwait(false); } }, cancellationToken)); }
static RemoteHostService() { // this is the very first service which will be called from client (VS) // we set up logger here RoslynLogger.SetLogger(new EtwLogger(GetLoggingChecker())); // Set this process's priority BelowNormal. // this should let us to freely try to use all resources possible without worrying about affecting // host's work such as responsiveness or build. Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal; }
public async Task SynchronizeGlobalAssetsAsync(Checksum[] checksums, CancellationToken cancellationToken) { using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizeGlobalAssetsAsync, Checksum.GetChecksumsLogInfo, checksums, cancellationToken)) { var assets = await RoslynServices.AssetService.GetAssetsAsync <object>(checksums, cancellationToken).ConfigureAwait(false); foreach (var asset in assets) { AssetStorage.TryAddGlobalAsset(asset.Item1, asset.Item2); } } }
/// <summary> /// Remote API. Initializes ServiceHub process global state. /// </summary> public void InitializeTelemetrySession( int hostProcessId, string serializedSession, CancellationToken cancellationToken ) { RunService( () => { var services = GetWorkspace().Services; var telemetryService = (RemoteWorkspaceTelemetryService)services.GetRequiredService <IWorkspaceTelemetryService>(); var telemetrySession = new TelemetrySession(serializedSession); telemetrySession.Start(); telemetryService.InitializeTelemetrySession(telemetrySession); telemetryService.RegisterUnexpectedExceptionLogger(Logger); // log telemetry that service hub started RoslynLogger.Log( FunctionId.RemoteHost_Connect, KeyValueLogMessage.Create( m => { m["Host"] = hostProcessId; m["InstanceId"] = InstanceId; } ) ); #if DEBUG // start performance reporter var diagnosticAnalyzerPerformanceTracker = services.GetService <IPerformanceTrackerService>(); if (diagnosticAnalyzerPerformanceTracker != null) { var globalOperationNotificationService = services.GetService <IGlobalOperationNotificationService>(); _performanceReporter = new PerformanceReporter( Logger, telemetrySession, diagnosticAnalyzerPerformanceTracker, globalOperationNotificationService, s_reportInterval, _shutdownCancellationSource.Token ); } #endif }, cancellationToken ); }
private async Task SerializeDiagnosticResultAsync(string streamName, DiagnosticAnalysisResultMap <string, DiagnosticAnalysisResultBuilder> result) { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_SerializeDiagnosticResultAsync, GetResultLogInfo, result, CancellationToken)) using (var stream = await DirectStream.GetAsync(streamName, CancellationToken).ConfigureAwait(false)) { using (var writer = new StreamObjectWriter(stream)) { DiagnosticResultSerializer.Serialize(writer, result, CancellationToken); } await stream.FlushAsync(CancellationToken).ConfigureAwait(false); } }
/// <summary> /// This is top level entry point for DesignerAttribute service from client (VS). /// /// This will be called by ServiceHub/JsonRpc framework /// </summary> public async Task <ImmutableArray <DesignerAttributeDocumentData> > ScanDesignerAttributesAsync(ProjectId projectId) { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_GetDesignerAttributesAsync, projectId.DebugName, CancellationToken)) { var solution = await GetSolutionAsync().ConfigureAwait(false); var project = solution.GetProject(projectId); var data = await AbstractDesignerAttributeService.TryAnalyzeProjectInCurrentProcessAsync( project, CancellationToken).ConfigureAwait(false); return(data.Values.ToImmutableArray()); } }
// TO-DO: More LSP.CompletionTriggerKind mappings are required to properly map to Roslyn CompletionTriggerKinds. // https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1178726 public static async Task <Completion.CompletionTrigger> LSPToRoslynCompletionTriggerAsync( LSP.CompletionContext?context, Document document, int position, CancellationToken cancellationToken) { if (context == null) { // Some LSP clients don't support sending extra context, so all we can do is invoke return(Completion.CompletionTrigger.Invoke); } else if (context.TriggerKind == LSP.CompletionTriggerKind.Invoked) { if (context is not LSP.VSCompletionContext vsCompletionContext) { return(Completion.CompletionTrigger.Invoke); } switch (vsCompletionContext.InvokeKind) { case LSP.VSCompletionInvokeKind.Explicit: return(Completion.CompletionTrigger.Invoke); case LSP.VSCompletionInvokeKind.Typing: var insertionChar = await GetInsertionCharacterAsync(document, position, cancellationToken).ConfigureAwait(false); return(Completion.CompletionTrigger.CreateInsertionTrigger(insertionChar)); case LSP.VSCompletionInvokeKind.Deletion: Contract.ThrowIfNull(context.TriggerCharacter); Contract.ThrowIfFalse(char.TryParse(context.TriggerCharacter, out var triggerChar)); return(Completion.CompletionTrigger.CreateDeletionTrigger(triggerChar)); default: // LSP added an InvokeKind that we need to support. Logger.Log(FunctionId.LSPCompletion_MissingLSPCompletionInvokeKind); return(Completion.CompletionTrigger.Invoke); } } else if (context.TriggerKind == LSP.CompletionTriggerKind.TriggerCharacter) { Contract.ThrowIfNull(context.TriggerCharacter); Contract.ThrowIfFalse(char.TryParse(context.TriggerCharacter, out var triggerChar)); return(Completion.CompletionTrigger.CreateInsertionTrigger(triggerChar)); } else { // LSP added a TriggerKind that we need to support. Logger.Log(FunctionId.LSPCompletion_MissingLSPCompletionTriggerKind); return(Completion.CompletionTrigger.Invoke); }
public override async Task <IList <(Checksum, object)> > RequestAssetsAsync(int scopeId, ISet <Checksum> checksums, ISerializerService serializerService, CancellationToken cancellationToken) { return(await _owner.RunServiceAsync(() => { using (RoslynLogger.LogBlock(FunctionId.SnapshotService_RequestAssetAsync, GetRequestLogInfo, scopeId, checksums, cancellationToken)) { return _owner.EndPoint.InvokeAsync( WellKnownServiceHubServices.AssetService_RequestAssetAsync, new object[] { scopeId, checksums.ToArray() }, (s, c) => Task.FromResult(ReadAssets(s, scopeId, checksums, serializerService, c)), cancellationToken); } }, cancellationToken).ConfigureAwait(false)); }
#pragma warning restore static RemoteHostService() { // this is the very first service which will be called from client (VS) // we set up logger here RoslynLogger.SetLogger(new EtwLogger(s_logChecker)); #if DEBUG // Make sure debug assertions in ServiceHub result in exceptions instead of the assertion UI Trace.Listeners.Clear(); Trace.Listeners.Add(new ThrowingTraceListener()); #endif SetNativeDllSearchDirectories(); }
public Task SynchronizeGlobalAssetsAsync(PinnedSolutionInfo solutionInfo, Checksum[] checksums, CancellationToken cancellationToken) { return(RunServiceAsync(async() => { using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizeGlobalAssetsAsync, Checksum.GetChecksumsLogInfo, checksums, cancellationToken)) { var assetProvider = SolutionService.CreateAssetProvider(solutionInfo, AssetStorage); var assets = await assetProvider.GetAssetsAsync <object>(checksums, cancellationToken).ConfigureAwait(false); foreach (var(checksum, value) in assets) { AssetStorage.TryAddGlobalAsset(checksum, value); } } }, cancellationToken)); }
private async Task SerializeDiagnosticResultAsync(string streamName, DiagnosticAnalysisResultMap <string, DiagnosticAnalysisResultBuilder> result, CancellationToken cancellationToken) { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_SerializeDiagnosticResultAsync, GetResultLogInfo, result, cancellationToken)) using (var stream = await DirectStream.GetAsync(streamName, cancellationToken).ConfigureAwait(false)) { using (var writer = new ObjectWriter(stream)) { var info = DiagnosticResultSerializer.Serialize(writer, result, cancellationToken); // save log for debugging Log(TraceEventType.Information, $"diagnostics: {info.diagnostics}, telemetry: {info.telemetry}, exceptions: {info.exceptions}"); } await stream.FlushAsync(cancellationToken).ConfigureAwait(false); } }
public static Completion.CompletionTriggerKind LSPToRoslynCompletionTriggerKind(LSP.CompletionTriggerKind triggerKind) { switch (triggerKind) { case LSP.CompletionTriggerKind.Invoked: return(Completion.CompletionTriggerKind.Invoke); case LSP.CompletionTriggerKind.TriggerCharacter: return(Completion.CompletionTriggerKind.Insertion); default: // LSP added a TriggerKind that we need to support. Logger.Log(FunctionId.LSPCompletion_MissingLSPCompletionTriggerKind); return(Completion.CompletionTriggerKind.Invoke); } }
public string Connect(string host, string serializedSession) { _primaryInstance = InstanceId; var existing = Interlocked.CompareExchange(ref _host, host, null); SetGlobalContext(serializedSession); if (existing != null && existing != host) { LogError($"{host} is given for {existing}"); } // log telemetry that service hub started RoslynLogger.Log(FunctionId.RemoteHost_Connect, KeyValueLogMessage.Create(SetSessionInfo)); return(_host); }
/// <summary> /// This is top level entry point for TodoComments service from client (VS). /// /// This will be called by ServiceHub/JsonRpc framework /// </summary> public async Task <IList <TodoComment> > GetTodoCommentsAsync(DocumentId documentId, ImmutableArray <TodoCommentDescriptor> tokens, CancellationToken cancellationToken) { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_GetTodoCommentsAsync, documentId.ProjectId.DebugName, cancellationToken)) { var solution = await GetSolutionAsync(cancellationToken).ConfigureAwait(false); var document = solution.GetDocument(documentId); var service = document.GetLanguageService <ITodoCommentService>(); if (service != null) { // todo comment service supported return(await service.GetTodoCommentsAsync(document, tokens, cancellationToken).ConfigureAwait(false)); } return(SpecializedCollections.EmptyList <TodoComment>()); } }
public void ReportAnalyzerPerformance(List <AnalyzerPerformanceInfo> snapshot, int unitCount, CancellationToken cancellationToken) { RunService(() => { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_ReportAnalyzerPerformance, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); var service = SolutionService.PrimaryWorkspace.Services.GetService <IPerformanceTrackerService>(); if (service == null) { return; } service.AddSnapshot(snapshot, unitCount); } }, cancellationToken); }
public override async Task <IList <ValueTuple <Checksum, object> > > RequestAssetsAsync(int sessionId, ISet <Checksum> checksums, CancellationToken callerCancellationToken) { // it should succeed as long as matching VS is alive // TODO: add logging mechanism using Logger // this can be called in two ways. // 1. Connection to get asset is closed (the asset source we were using is disconnected - _assetChannelCancellationToken) // if this asset source's channel is closed, service will move to next asset source to get the asset as long as callerCancellationToken // is not cancelled // // 2. Request to required this asset has cancelled. (callerCancellationToken) using (var mergedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(_owner.CancellationToken, callerCancellationToken)) using (RoslynLogger.LogBlock(FunctionId.SnapshotService_RequestAssetAsync, GetRequestLogInfo, sessionId, checksums, mergedCancellationToken.Token)) { return(await _owner.Rpc.InvokeAsync(WellKnownServiceHubServices.AssetService_RequestAssetAsync, new object[] { sessionId, checksums.ToArray() }, (s, c) => ReadAssets(s, sessionId, checksums, c), mergedCancellationToken.Token).ConfigureAwait(false)); } }
/// <summary> /// This is top level entry point for DesignerAttribute service from client (VS). /// /// This will be called by ServiceHub/JsonRpc framework /// </summary> public async Task <IList <DesignerAttributeDocumentData> > ScanDesignerAttributesAsync(ProjectId projectId, CancellationToken cancellationToken) { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_GetDesignerAttributesAsync, projectId.DebugName, cancellationToken)) { var solution = await GetSolutionAsync(cancellationToken).ConfigureAwait(false); var project = solution.GetProject(projectId); var data = await AbstractDesignerAttributeService.TryAnalyzeProjectInCurrentProcessAsync( project, cancellationToken).ConfigureAwait(false); if (data.Count == 0) { return(SpecializedCollections.EmptyList <DesignerAttributeDocumentData>()); } return(data.Values.ToList()); } }
private static void SetGlobalContext(string serializedSession) { // set global telemetry session var session = GetTelemetrySession(serializedSession); if (session == null) { return; } // set roslyn loggers WatsonReporter.SetTelemetrySession(session); RoslynLogger.SetLogger(AggregateLogger.Create(new VSTelemetryLogger(session), RoslynLogger.GetLogger())); // set both handler as NFW FatalError.Handler = WatsonReporter.Report; FatalError.NonFatalHandler = WatsonReporter.Report; }
public override async Task <IList <(Checksum, object)> > RequestAssetsAsync(int scopeId, ISet <Checksum> checksums, ISerializerService serializerService, CancellationToken callerCancellation) { using (RoslynLogger.LogBlock(FunctionId.SnapshotService_RequestAssetAsync, GetRequestLogInfo, scopeId, checksums, callerCancellation)) { try { return(await _owner.RunServiceAsync(cancellationToken => { return _owner.InvokeAsync(WellKnownServiceHubServices.AssetService_RequestAssetAsync, new object[] { scopeId, checksums.ToArray() }, (s, c) => ReadAssets(s, scopeId, checksums, serializerService, c), cancellationToken); }, callerCancellation).ConfigureAwait(false)); } catch (Exception ex) when(ReportUnlessCanceled(ex, callerCancellation)) { throw ExceptionUtilities.Unreachable; } } }
/// <summary> /// This is top level entry point for DesignerAttribute service from client (VS). /// /// This will be called by ServiceHub/JsonRpc framework /// </summary> public Task <DesignerAttributeResult> ScanDesignerAttributesAsync(DocumentId documentId, CancellationToken cancellationToken) { return(RunServiceAsync(async() => { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_GetDesignerAttributesAsync, documentId.DebugName, cancellationToken)) { var solution = await GetSolutionAsync(cancellationToken).ConfigureAwait(false); var document = solution.GetDocument(documentId); var service = document.GetLanguageService <IDesignerAttributeService>(); if (service != null) { // todo comment service supported return await service.ScanDesignerAttributesAsync(document, cancellationToken).ConfigureAwait(false); } return new DesignerAttributeResult(designerAttributeArgument: null, containsErrors: true, applicable: false); } }, cancellationToken)); }
protected override async Task ExecuteAsync() { // wait for global operation such as build await GlobalOperationTask.ConfigureAwait(false); using (var pooledObject = SharedPools.Default <List <ExpensiveAnalyzerInfo> >().GetPooledObject()) using (RoslynLogger.LogBlock(FunctionId.Diagnostics_GeneratePerformaceReport, CancellationToken)) { _diagnosticAnalyzerPerformanceTracker.GenerateReport(pooledObject.Object); foreach (var analyzerInfo in pooledObject.Object) { var newAnalyzer = _reported.Add(analyzerInfo.AnalyzerId); var isInternalUser = _telemetrySession.IsUserMicrosoftInternal; // we only report same analyzer once unless it is internal user if (isInternalUser || newAnalyzer) { // this will report telemetry under VS. this will let us see how accurate our performance tracking is RoslynLogger.Log(FunctionId.Diagnostics_BadAnalyzer, KeyValueLogMessage.Create(m => { // since it is telemetry, we hash analyzer name if it is not builtin analyzer m[nameof(analyzerInfo.AnalyzerId)] = isInternalUser ? analyzerInfo.AnalyzerId : analyzerInfo.PIISafeAnalyzerId; m[nameof(analyzerInfo.LocalOutlierFactor)] = analyzerInfo.LocalOutlierFactor; m[nameof(analyzerInfo.Average)] = analyzerInfo.Average; m[nameof(analyzerInfo.AdjustedStandardDeviation)] = analyzerInfo.AdjustedStandardDeviation; })); } // for logging, we only log once. we log here so that we can ask users to provide this log to us // when we want to find out VS performance issue that could be caused by analyzer if (newAnalyzer) { _logger.TraceEvent(TraceEventType.Warning, 0, $"Analyzer perf indicators exceeded threshold for '{analyzerInfo.AnalyzerId}' ({analyzerInfo.AnalyzerIdHash}): " + $"LOF: {analyzerInfo.LocalOutlierFactor}, Avg: {analyzerInfo.Average}, Stddev: {analyzerInfo.AdjustedStandardDeviation}"); } } } }
public async Task SynchronizePrimaryWorkspaceAsync(Checksum checksum) { using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_Synchronize, c => c.ToString(), checksum, CancellationToken)) { try { await RoslynServices.SolutionService.UpdatePrimaryWorkspaceAsync(checksum, CancellationToken).ConfigureAwait(false); } catch (IOException) { // stream to send over assets has closed before we // had chance to check cancellation } catch (OperationCanceledException) { // rpc connection has closed. // this can happen if client side cancelled the // operation } } }
#pragma warning restore #endif static RemoteHostService() { if (GCSettings.IsServerGC) { // Server GC runs processor-affinitized threads with high priority. To avoid interfering with other // applications while still allowing efficient out-of-process execution, slightly reduce the process // priority when using server GC. Process.GetCurrentProcess().TrySetPriorityClass(ProcessPriorityClass.BelowNormal); } // this is the very first service which will be called from client (VS) // we set up logger here RoslynLogger.SetLogger(new EtwLogger(s_logChecker)); #if DEBUG // Make sure debug assertions in ServiceHub result in exceptions instead of the assertion UI Trace.Listeners.Clear(); Trace.Listeners.Add(new ThrowingTraceListener()); #endif SetNativeDllSearchDirectories(); }
public string Connect(string host, int uiCultureLCID, int cultureLCID, string?serializedSession, CancellationToken cancellationToken) { return(RunService(() => { cancellationToken.ThrowIfCancellationRequested(); // initialize global assert storage AssetStorage.Initialize(this); _primaryInstance = InstanceId; var existing = Interlocked.CompareExchange(ref _host, host, null); // serializedSession may be null for testing if (serializedSession != null) { SetGlobalContext(uiCultureLCID, cultureLCID, serializedSession); } if (existing != null && existing != host) { Log(TraceEventType.Error, $"{host} is given for {existing}"); } // log telemetry that service hub started RoslynLogger.Log(FunctionId.RemoteHost_Connect, KeyValueLogMessage.Create(SetSessionInfo)); if (serializedSession != null) { // Set this process's priority BelowNormal. // this should let us to freely try to use all resources possible without worrying about affecting // host's work such as responsiveness or build. Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal; } return _host; }, cancellationToken)); }
// TO-DO: More LSP.CompletionTriggerKind mappings are required to properly map to Roslyn CompletionTriggerKinds. // https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1178726 public static Completion.CompletionTrigger LSPToRoslynCompletionTrigger(LSP.CompletionContext?context) { if (context == null) { // Some LSP clients don't support sending extra context, so all we can do is invoke return(Completion.CompletionTrigger.Invoke); } else if (context.TriggerKind == LSP.CompletionTriggerKind.Invoked) { return(Completion.CompletionTrigger.Invoke); } else if (context.TriggerKind == LSP.CompletionTriggerKind.TriggerCharacter) { Contract.ThrowIfNull(context.TriggerCharacter); return(Completion.CompletionTrigger.CreateInsertionTrigger(char.Parse(context.TriggerCharacter))); } else { // LSP added a TriggerKind that we need to support. Logger.Log(FunctionId.LSPCompletion_MissingLSPCompletionTriggerKind); return(Completion.CompletionTrigger.Invoke); } }
/// <summary> /// Calculate dignostics. this works differently than other ones such as todo comments or designer attribute scanner /// since in proc and out of proc runs quite differently due to concurrency and due to possible amount of data /// that needs to pass through between processes /// </summary> public Task CalculateDiagnosticsAsync(PinnedSolutionInfo solutionInfo, DiagnosticArguments arguments, string pipeName, CancellationToken cancellationToken) { return(RunServiceAsync(async() => { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_CalculateDiagnosticsAsync, arguments.ProjectId.DebugName, cancellationToken)) using (arguments.IsHighPriority ? UserOperationBooster.Boost() : default) { var solutionService = CreateSolutionService(solutionInfo); var solution = await solutionService.GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); var documentId = arguments.DocumentId; var projectId = arguments.ProjectId; var project = solution.GetProject(projectId); var documentSpan = arguments.DocumentSpan; var documentAnalysisKind = arguments.DocumentAnalysisKind; var diagnosticComputer = new DiagnosticComputer(documentId, project, documentSpan, documentAnalysisKind, _analyzerInfoCache); var result = await diagnosticComputer.GetDiagnosticsAsync( arguments.AnalyzerIds, reportSuppressedDiagnostics: arguments.ReportSuppressedDiagnostics, logPerformanceInfo: arguments.LogPerformanceInfo, getTelemetryInfo: arguments.GetTelemetryInfo, cancellationToken).ConfigureAwait(false); await RemoteEndPoint.WriteDataToNamedPipeAsync(pipeName, (result, documentAnalysisKind), (writer, data, cancellationToken) => { var(diagnostics, telemetry) = DiagnosticResultSerializer.WriteDiagnosticAnalysisResults(writer, data.documentAnalysisKind, data.result, cancellationToken); // save log for debugging Log(TraceEventType.Information, $"diagnostics: {diagnostics}, telemetry: {telemetry}"); return Task.CompletedTask; }, cancellationToken).ConfigureAwait(false); } }, cancellationToken)); }
public async Task SynchronizeAsync(byte[] solutionChecksum) { var checksum = new Checksum(solutionChecksum); using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_Synchronize, c => c.ToString(), checksum, CancellationToken)) { try { // cause all assets belong to the given solution to sync to remote host await RoslynServices.AssetService.SynchronizeSolutionAssetsAsync(checksum, CancellationToken).ConfigureAwait(false); } catch (IOException) { // stream to send over assets has closed before we // had chance to check cancellation } catch (OperationCanceledException) { // rpc connection has closed. // this can happen if client side cancelled the // operation } } }