/// <summary> /// Ensures that <see cref="_currentAggregateProjectContext"/> is updated for the latest TargetFrameworks from the project properties /// and returns this value. /// </summary> private async Task <AggregateWorkspaceProjectContext> UpdateProjectContextAsync() { // Ensure that only single thread is attempting to create a project context. AggregateWorkspaceProjectContext previousContextToDispose = null; using (await _gate.DisposableWaitAsync().ConfigureAwait(false)) { // Check if we have already computed the project context. if (_currentAggregateProjectContext != null) { // For non-cross targeting projects, we can use the current project context. // For cross-targeting projects, we need to verify that the TargetFrameworks for the current project context matches latest TargetFrameworks project property value. // If not, we create a new one and dispose the current one. if (!_currentAggregateProjectContext.IsCrossTargeting) { return(_currentAggregateProjectContext); } var projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync().ConfigureAwait(false); var targetFrameworks = (string)await projectProperties.TargetFrameworks.GetValueAsync().ConfigureAwait(false); if (_currentAggregateProjectContext.HasMatchingTargetFrameworks(targetFrameworks)) { return(_currentAggregateProjectContext); } previousContextToDispose = _currentAggregateProjectContext; } // Force refresh the CPS active project configuration (needs UI thread). await _commonServices.ThreadingService.SwitchToUIThread(); await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync().ConfigureAwait(false); // Create new project context. _currentAggregateProjectContext = await _contextProvider.Value.CreateProjectContextAsync().ConfigureAwait(false); // Dispose the old project context, if one exists. if (previousContextToDispose != null) { await _contextProvider.Value.ReleaseProjectContextAsync(previousContextToDispose).ConfigureAwait(false); foreach (var innerContext in previousContextToDispose.DisposedInnerProjectContexts) { foreach (var handler in Handlers) { await handler.Value.OnContextReleasedAsync(innerContext).ConfigureAwait(false); } } } return(_currentAggregateProjectContext); } }
/// <summary> /// Ensures that <see cref="_currentAggregateProjectContext"/> is updated for the latest target frameworks from the project properties /// and returns this value. /// </summary> private async Task <AggregateWorkspaceProjectContext> UpdateProjectContextAsync() { // Ensure that only single thread is attempting to create a project context. AggregateWorkspaceProjectContext previousContextToDispose = null; return(await ExecuteWithinLockAsync(async() => { await _commonServices.ThreadingService.SwitchToUIThread(); string newTargetFramework = null; var projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync().ConfigureAwait(false); // Check if we have already computed the project context. if (_currentAggregateProjectContext != null) { // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed. // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project. // If not, we create a new one and dispose the current one. if (!_currentAggregateProjectContext.IsCrossTargeting) { newTargetFramework = (string)await projectProperties.TargetFramework.GetValueAsync().ConfigureAwait(false); if (StringComparers.PropertyValues.Equals(_currentTargetFramework, newTargetFramework)) { return _currentAggregateProjectContext; } // Dispose the old workspace project context for the previous target framework. await DisposeAggregateProjectContextAsync(_currentAggregateProjectContext).ConfigureAwait(false); } else { // Check if the current project context is up-to-date for the current active and known project configurations. var activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; var knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync().ConfigureAwait(false); if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) && _currentAggregateProjectContext.HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations)) { return _currentAggregateProjectContext; } previousContextToDispose = _currentAggregateProjectContext; } } else { newTargetFramework = (string)await projectProperties.TargetFramework.GetValueAsync().ConfigureAwait(false); } // Force refresh the CPS active project configuration (needs UI thread). await _commonServices.ThreadingService.SwitchToUIThread(); await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync().ConfigureAwait(false); // Create new project context. _currentAggregateProjectContext = await _contextProvider.Value.CreateProjectContextAsync().ConfigureAwait(false); _currentTargetFramework = newTargetFramework; // Dispose the old project context, if one exists. if (previousContextToDispose != null) { await DisposeAggregateProjectContextAsync(previousContextToDispose).ConfigureAwait(false); } return _currentAggregateProjectContext; })); }