public override async Task <string> OnGetEvaluatedPropertyValueAsync(string evaluatedPropertyValue, IProjectProperties defaultProperties) { ActiveConfiguredObjects <ConfiguredProject>?configuredProjects = await _projectProvider.GetActiveConfiguredProjectsAsync(); if (configuredProjects == null) { return(""); } var builder = PooledArray <string> .GetInstance(); foreach (ConfiguredProject configuredProject in configuredProjects.Objects) { ProjectProperties projectProperties = configuredProject.Services.ExportProvider.GetExportedValue <ProjectProperties>(); ConfigurationGeneral configuration = await projectProperties.GetConfigurationGeneralPropertiesAsync(); string?currentTargetFrameworkMoniker = (string?)await configuration.TargetFrameworkMoniker.GetValueAsync(); Assumes.NotNull(currentTargetFrameworkMoniker); builder.Add(currentTargetFrameworkMoniker !); } return(string.Join(";", builder.ToArrayAndFree())); }
public override async Task <string?> OnSetPropertyValueAsync( string propertyName, string unevaluatedPropertyValue, IProjectProperties defaultProperties, IReadOnlyDictionary <string, string>?dimensionalConditions = null) { ConfigurationGeneral configuration = await _properties.GetConfigurationGeneralPropertiesAsync(); string?currentTargetFramework = (string?)await configuration.TargetFramework.GetValueAsync(); string?currentTargetFrameworks = (string?)await configuration.TargetFrameworks.GetValueAsync(); if (!string.IsNullOrEmpty(currentTargetFrameworks)) { throw new InvalidOperationException(VSResources.MultiTFEditNotSupported); } else if (!string.IsNullOrEmpty(currentTargetFramework)) { await defaultProperties.SetPropertyValueAsync(ConfigurationGeneral.TargetFrameworkProperty, unevaluatedPropertyValue); } else { // CPS implements IVsHierarchy.SetProperty for the TFM property to call through the multi-targeting service and change the TFM. // This causes the project to be reloaded after changing the values. // Since the property providers are called under a write-lock, trying to reload the project on the same context fails saying it can't load the project // if a lock is held. We are not going to write to the file under this lock (we return null from this method) and so we fork execution here to schedule // a lambda on the UI thread and we don't pass the lock information from this context to the new one. _unconfiguredProjectVsServices.ThreadingService.RunAndForget(() => { _unconfiguredProjectVsServices.VsHierarchy.SetProperty(HierarchyId.Root, (int)VsHierarchyPropID.TargetFrameworkMoniker, unevaluatedPropertyValue); return(System.Threading.Tasks.Task.CompletedTask); }, options: ForkOptions.HideLocks | ForkOptions.StartOnMainThread, unconfiguredProject: _unconfiguredProjectVsServices.Project); } return(null); }
public async Task <AggregateCrossTargetProjectContext> CreateProjectContextAsync() { // Get the set of active configured projects ignoring target framework. #pragma warning disable CS0618 // Type or member is obsolete ImmutableDictionary <string, ConfiguredProject> configuredProjectsMap = await _activeConfiguredProjectsProvider.GetActiveConfiguredProjectsMapAsync(); #pragma warning restore CS0618 // Type or member is obsolete ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; ImmutableArray <ITargetFramework> .Builder targetFrameworks = ImmutableArray.CreateBuilder <ITargetFramework>(initialCapacity: configuredProjectsMap.Count); ITargetFramework activeTargetFramework = TargetFramework.Empty; foreach ((string tfm, ConfiguredProject configuredProject) in configuredProjectsMap) { ProjectProperties projectProperties = configuredProject.Services.ExportProvider.GetExportedValue <ProjectProperties>(); ConfigurationGeneral configurationGeneralProperties = await projectProperties.GetConfigurationGeneralPropertiesAsync(); ITargetFramework targetFramework = await GetTargetFrameworkAsync(tfm, configurationGeneralProperties); targetFrameworks.Add(targetFramework); if (activeTargetFramework.Equals(TargetFramework.Empty) && configuredProject.ProjectConfiguration.Equals(activeProjectConfiguration)) { activeTargetFramework = targetFramework; } } bool isCrossTargeting = !(configuredProjectsMap.Count == 1 && string.IsNullOrEmpty(configuredProjectsMap.First().Key)); return(new AggregateCrossTargetProjectContext( isCrossTargeting, targetFrameworks.MoveToImmutable(), configuredProjectsMap, activeTargetFramework, _targetFrameworkProvider)); }
private async Task <string?> GetTemplateLanguageAsync() { ConfigurationGeneral general = await _properties.GetConfigurationGeneralPropertiesAsync(); return((string?)await general.TemplateLanguage.GetValueAsync()); }
/// <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; ConfigurationGeneral 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. ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; IImmutableSet <ProjectConfiguration> 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; }).ConfigureAwait(false)); }
private async Task <Guid> GetLanguageServiceId() { ConfigurationGeneral properties = await _projectVsServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync(); return(await properties.LanguageServiceId.GetValueAsGuidAsync()); }
/// <summary> /// Determines whether the current project context object is out of date based on the project's target frameworks. /// If so, a new one is created and subscriptions are updated accordingly. /// </summary> private async Task UpdateProjectContextAndSubscriptionsAsync() { // Ensure that only single thread is attempting to create a project context. AggregateCrossTargetProjectContext newProjectContext = await ExecuteWithinLockAsync(TryUpdateCurrentAggregateProjectContextAsync); if (newProjectContext != null) { // Dispose existing subscriptions. DisposeAndClearSubscriptions(); // Add subscriptions for the configured projects in the new project context. await AddSubscriptionsAsync(newProjectContext); } return; async Task <AggregateCrossTargetProjectContext> TryUpdateCurrentAggregateProjectContextAsync() { AggregateCrossTargetProjectContext previousContext = _currentAggregateProjectContext; // Check if we have already computed the project context. if (previousContext != 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. ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync(); if (!previousContext.IsCrossTargeting) { string newTargetFrameworkName = (string)await projectProperties.TargetFramework.GetValueAsync(); ITargetFramework newTargetFramework = _targetFrameworkProvider.GetTargetFramework(newTargetFrameworkName); if (previousContext.ActiveTargetFramework.Equals(newTargetFramework)) { // No change return(null); } } else { // Check if the current project context is up-to-date for the current active and known project configurations. ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync(); if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) && HasMatchingTargetFrameworks(previousContext, activeProjectConfiguration, knownProjectConfigurations)) { // No change return(null); } } } // Force refresh the CPS active project configuration (needs UI thread). await _commonServices.ThreadingService.SwitchToUIThread(); await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync(); // Create new project context. AggregateCrossTargetProjectContext newContext = await _contextProvider.Value.CreateProjectContextAsync(); _currentAggregateProjectContext = newContext; OnAggregateContextChanged(previousContext, newContext); return(newContext); } bool HasMatchingTargetFrameworks( AggregateCrossTargetProjectContext previousContext, ProjectConfiguration activeProjectConfiguration, IReadOnlyCollection <ProjectConfiguration> knownProjectConfigurations) { Assumes.True(activeProjectConfiguration.IsCrossTargeting()); ITargetFramework activeTargetFramework = _targetFrameworkProvider.GetTargetFramework(activeProjectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]); if (!previousContext.ActiveTargetFramework.Equals(activeTargetFramework)) { // Active target framework is different. return(false); } var targetFrameworkMonikers = knownProjectConfigurations .Select(c => c.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]) .Distinct() .ToList(); if (targetFrameworkMonikers.Count != previousContext.TargetFrameworks.Length) { // Different number of target frameworks. return(false); } foreach (string targetFrameworkMoniker in targetFrameworkMonikers) { ITargetFramework targetFramework = _targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker); if (!previousContext.TargetFrameworks.Contains(targetFramework)) { // Differing TargetFramework return(false); } } return(true); } void OnAggregateContextChanged( AggregateCrossTargetProjectContext oldContext, AggregateCrossTargetProjectContext newContext) { if (oldContext == null) { // all new rules will be sent to new context, we don't need to clean up anything return; } var targetsToClean = new HashSet <ITargetFramework>(); ImmutableArray <ITargetFramework> oldTargets = oldContext.TargetFrameworks; if (newContext == null) { targetsToClean.AddRange(oldTargets); } else { ImmutableArray <ITargetFramework> newTargets = newContext.TargetFrameworks; targetsToClean.AddRange(oldTargets.Except(newTargets)); } if (targetsToClean.Count != 0) { TryUpdateSnapshot(snapshot => snapshot.RemoveTargets(targetsToClean)); } } }
private async Task <string> GetTargetPathAsync() { ConfigurationGeneral properties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync(); return((string)await properties.TargetPath.GetValueAsync()); }
private async Task <ComplexTargetFramework> GetStoredPropertiesAsync() { ConfigurationGeneral configuration = await _properties.GetConfigurationGeneralPropertiesAsync(); return(await GetStoredComplexTargetFrameworkAsync(configuration)); }
private static async Task <ComplexTargetFramework> GetStoredComplexTargetFrameworkAsync(ConfigurationGeneral configuration) { ComplexTargetFramework storedValues = new ComplexTargetFramework { TargetFrameworkMoniker = (string?)await configuration.TargetFrameworkMoniker.GetValueAsync(), TargetPlatformIdentifier = (string?)await configuration.TargetPlatformIdentifier.GetValueAsync(), TargetPlatformVersion = (string?)await configuration.TargetPlatformVersion.GetValueAsync(), TargetFramework = (string?)await configuration.TargetFramework.GetValueAsync() }; return(storedValues); }
public async Task <AggregateCrossTargetProjectContext?> TryUpdateCurrentAggregateProjectContextAsync() { AggregateCrossTargetProjectContext?previousContext = Current; // Check if we have already computed the project context. if (previousContext != 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. ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync(); if (!previousContext.IsCrossTargeting) { string?newTargetFrameworkName = (string?)await projectProperties.TargetFrameworkMoniker.GetValueAsync(); if (string.IsNullOrEmpty(newTargetFrameworkName) && TargetFramework.Empty.Equals(previousContext.ActiveTargetFramework)) { // No change return(null); } TargetFramework?newTargetFramework = _targetFrameworkProvider.GetTargetFramework(newTargetFrameworkName); if (previousContext.ActiveTargetFramework.Equals(newTargetFramework)) { // No change return(null); } } else { // Check if the current project context is up-to-date for the current active and known project configurations. Assumes.Present(_commonServices.Project.Services.ProjectConfigurationsService); ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync(); if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) && HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations)) { // No change return(null); } } } // Force refresh the CPS active project configuration (needs UI thread). await _commonServices.ThreadingService.SwitchToUIThread(); await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync(); // Create new project context. AggregateCrossTargetProjectContext newContext = await _contextProvider.Value.CreateProjectContextAsync(); Current = newContext; return(newContext); bool HasMatchingTargetFrameworks( ProjectConfiguration activeProjectConfiguration, IReadOnlyCollection <ProjectConfiguration> knownProjectConfigurations) { Assumes.NotNull(previousContext); Assumes.True(activeProjectConfiguration.IsCrossTargeting()); TargetFramework?activeTargetFramework = _targetFrameworkProvider.GetTargetFramework(activeProjectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]); if (!previousContext.ActiveTargetFramework.Equals(activeTargetFramework)) { // Active target framework is different. return(false); } var targetFrameworkMonikers = knownProjectConfigurations .Select(c => c.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]) .Distinct() .ToList(); if (targetFrameworkMonikers.Count != previousContext.TargetFrameworks.Length) { // Different number of target frameworks. return(false); } foreach (string targetFrameworkMoniker in targetFrameworkMonikers) { TargetFramework?targetFramework = _targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker); if (targetFramework == null || !previousContext.TargetFrameworks.Contains(targetFramework)) { // Differing TargetFramework return(false); } } return(true); } }
private async Task <AggregateWorkspaceProjectContext> CreateProjectContextAsyncCore() { string languageName = await GetLanguageServiceName().ConfigureAwait(false); if (string.IsNullOrEmpty(languageName)) { return(null); } Guid projectGuid = await _projectGuidService.GetProjectGuidAsync() .ConfigureAwait(false); string targetPath = await GetTargetPathAsync().ConfigureAwait(false); if (string.IsNullOrEmpty(targetPath)) { return(null); } // TODO: https://github.com/dotnet/roslyn-project-system/issues/353 await _commonServices.ThreadingService.SwitchToUIThread(); ProjectData projectData = GetProjectData(); // Get the set of active configured projects ignoring target framework. #pragma warning disable CS0618 // Type or member is obsolete ImmutableDictionary <string, ConfiguredProject> configuredProjectsMap = await _activeConfiguredProjectsProvider.GetActiveConfiguredProjectsMapAsync().ConfigureAwait(true); #pragma warning restore CS0618 // Type or member is obsolete // Get the unconfigured project host object (shared host object). var configuredProjectsToRemove = new HashSet <ConfiguredProject>(_configuredProjectHostObjectsMap.Keys); ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; ImmutableDictionary <string, IWorkspaceProjectContext> .Builder innerProjectContextsBuilder = ImmutableDictionary.CreateBuilder <string, IWorkspaceProjectContext>(); string activeTargetFramework = string.Empty; IConfiguredProjectHostObject activeIntellisenseProjectHostObject = null; foreach (KeyValuePair <string, ConfiguredProject> kvp in configuredProjectsMap) { string targetFramework = kvp.Key; ConfiguredProject configuredProject = kvp.Value; if (!TryGetConfiguredProjectState(configuredProject, out IWorkspaceProjectContext workspaceProjectContext, out IConfiguredProjectHostObject configuredProjectHostObject)) { // Get the target path for the configured project. ProjectProperties projectProperties = configuredProject.Services.ExportProvider.GetExportedValue <ProjectProperties>(); ConfigurationGeneral configurationGeneralProperties = await projectProperties.GetConfigurationGeneralPropertiesAsync().ConfigureAwait(true); targetPath = (string)await configurationGeneralProperties.TargetPath.GetValueAsync().ConfigureAwait(true); string targetFrameworkMoniker = (string)await configurationGeneralProperties.TargetFrameworkMoniker.GetValueAsync().ConfigureAwait(true); string workspaceProjectContextId = GetWorkspaceContextId(configuredProject); configuredProjectHostObject = _projectHostProvider.GetConfiguredProjectHostObject(_unconfiguredProjectHostObject, workspaceProjectContextId, targetFrameworkMoniker); // TODO: https://github.com/dotnet/roslyn-project-system/issues/353 await _commonServices.ThreadingService.SwitchToUIThread(); // NOTE: Despite CreateProjectContext taking a "displayName"; it's actually sets both "WorkspaceProjectContextId", "DisplayName", and default "AssemblyName". // Unlike the latter properties, we cannot change WorkspaceProjectContextId once set, so we pass it as the display name. workspaceProjectContext = _contextFactory.Value.CreateProjectContext(languageName, workspaceProjectContextId, projectData.FullPath, projectGuid, configuredProjectHostObject, targetPath); workspaceProjectContext.DisplayName = GetDisplayName(configuredProject, projectData, targetFramework); // By default, set "LastDesignTimeBuildSucceeded = false" to turn off diagnostics until first design time build succeeds for this project. workspaceProjectContext.LastDesignTimeBuildSucceeded = false; AddConfiguredProjectState(configuredProject, workspaceProjectContext, configuredProjectHostObject); } innerProjectContextsBuilder.Add(targetFramework, workspaceProjectContext); if (activeIntellisenseProjectHostObject == null && configuredProject.ProjectConfiguration.Equals(activeProjectConfiguration)) { activeIntellisenseProjectHostObject = configuredProjectHostObject; activeTargetFramework = targetFramework; } } _unconfiguredProjectHostObject.ActiveIntellisenseProjectHostObject = activeIntellisenseProjectHostObject; return(new AggregateWorkspaceProjectContext(innerProjectContextsBuilder.ToImmutable(), configuredProjectsMap, activeTargetFramework, _unconfiguredProjectHostObject)); }
public Init(ConfigurationGeneral configurationGeneral) { this.mConfigurationGeneral = configurationGeneral; }
// Returns the name that is the handshake between Roslyn and the csproj/vbproj private async Task <string> GetLanguageServiceName() { ConfigurationGeneral properties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync(); return((string)await properties.LanguageServiceName.GetValueAsync()); }