private async Task AddSubscriptionsAsync(AggregateWorkspaceProjectContext newProjectContext)
        {
            Requires.NotNull(newProjectContext, nameof(newProjectContext));

            await _commonServices.ThreadingService.SwitchToUIThread();

            await _tasksService.LoadedProjectAsync(() =>
            {
                IEnumerable <string> watchedEvaluationRules      = _languageServiceHandlerManager.GetWatchedRules(RuleHandlerType.Evaluation);
                IEnumerable <string> watchedDesignTimeBuildRules = _languageServiceHandlerManager.GetWatchedRules(RuleHandlerType.DesignTimeBuild);

                foreach (ConfiguredProject configuredProject in newProjectContext.InnerConfiguredProjects)
                {
                    if (_projectConfigurationsWithSubscriptions.Contains(configuredProject.ProjectConfiguration))
                    {
                        continue;
                    }

                    _designTimeBuildSubscriptionLinks.Add(configuredProject.Services.ProjectSubscription.JointRuleSource.SourceBlock.LinkTo(
                                                              new ActionBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(e => OnProjectChangedCoreAsync(e, RuleHandlerType.DesignTimeBuild)),
                                                              ruleNames: watchedDesignTimeBuildRules, suppressVersionOnlyUpdates: true));

                    _evaluationSubscriptionLinks.Add(configuredProject.Services.ProjectSubscription.ProjectRuleSource.SourceBlock.LinkTo(
                                                         new ActionBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(e => OnProjectChangedCoreAsync(e, RuleHandlerType.Evaluation)),
                                                         ruleNames: watchedEvaluationRules, suppressVersionOnlyUpdates: true));

                    _projectConfigurationsWithSubscriptions.Add(configuredProject.ProjectConfiguration);
                }

                return(Task.CompletedTask);
            });
        }
        private async Task AddSubscriptionsAsync(AggregateWorkspaceProjectContext newProjectContext)
        {
            Requires.NotNull(newProjectContext, nameof(newProjectContext));

            await _commonServices.ThreadingService.SwitchToUIThread();

            using (_tasksService.LoadedProject())
            {
                var watchedEvaluationRules      = GetWatchedRules(RuleHandlerType.Evaluation);
                var watchedDesignTimeBuildRules = GetWatchedRules(RuleHandlerType.DesignTimeBuild);

                foreach (var configuredProject in newProjectContext.InnerConfiguredProjects)
                {
                    if (_projectConfigurationsWithSubscriptions.Contains(configuredProject.ProjectConfiguration))
                    {
                        continue;
                    }

                    _designTimeBuildSubscriptionLinks.Add(configuredProject.Services.ProjectSubscription.JointRuleSource.SourceBlock.LinkTo(
                                                              new ActionBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(e => OnProjectChangedCoreAsync(e, RuleHandlerType.DesignTimeBuild)),
                                                              ruleNames: watchedDesignTimeBuildRules.Union(watchedEvaluationRules), suppressVersionOnlyUpdates: true));

                    _evaluationSubscriptionLinks.Add(configuredProject.Services.ProjectSubscription.ProjectRuleSource.SourceBlock.LinkTo(
                                                         new ActionBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(e => OnProjectChangedCoreAsync(e, RuleHandlerType.Evaluation)),
                                                         ruleNames: watchedEvaluationRules, suppressVersionOnlyUpdates: true));

                    _projectConfigurationsWithSubscriptions.Add(configuredProject.ProjectConfiguration);
                }
            }
        }
        private async Task DisposeAggregateProjectContextAsync(AggregateWorkspaceProjectContext projectContext)
        {
            await _contextProvider.Value.ReleaseProjectContextAsync(projectContext).ConfigureAwait(false);

            foreach (IWorkspaceProjectContext innerContext in projectContext.DisposedInnerProjectContexts)
            {
                _languageServiceHandlerManager.OnContextReleased(innerContext);
            }
        }
Esempio n. 4
0
        /// <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);
            }
        }
        private async Task UpdateProjectContextAndSubscriptionsAsync()
        {
            AggregateWorkspaceProjectContext previousProjectContext = _currentAggregateProjectContext;
            AggregateWorkspaceProjectContext newProjectContext      = await UpdateProjectContextAsync().ConfigureAwait(false);

            if (previousProjectContext != newProjectContext)
            {
                // Add subscriptions for the new configured projects in the new project context.
                await AddSubscriptionsAsync(newProjectContext).ConfigureAwait(false);
            }
        }
        private async Task DisposeAggregateProjectContextAsync(AggregateWorkspaceProjectContext projectContext)
        {
            await _contextProvider.Value.ReleaseProjectContextAsync(projectContext).ConfigureAwait(false);

            foreach (var innerContext in projectContext.DisposedInnerProjectContexts)
            {
                foreach (var handler in Handlers)
                {
                    await handler.Value.OnContextReleasedAsync(innerContext).ConfigureAwait(false);
                }
            }
        }
        /// <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;
            }));
        }