Skip to content

Commit bff510e

Browse files
authored
Lazily load unconfigured project only when it's needed (#7238)
1 parent 13353c2 commit bff510e

5 files changed

Lines changed: 34 additions & 17 deletions

File tree

src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/CpsPackageReferenceProject.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using NuGet.VisualStudio;
2929
using PackageReference = NuGet.Packaging.PackageReference;
3030
using Task = System.Threading.Tasks.Task;
31+
using VSThreading = Microsoft.VisualStudio.Threading;
3132

3233
namespace NuGet.PackageManagement.VisualStudio
3334
{
@@ -43,14 +44,14 @@ public class CpsPackageReferenceProject : PackageReferenceProject<List<Framework
4344
private const string TargetFrameworkCondition = "TargetFramework";
4445

4546
private readonly IProjectSystemCache _projectSystemCache;
46-
private readonly UnconfiguredProject _unconfiguredProject;
47+
private readonly VSThreading.AsyncLazy<UnconfiguredProject> _unconfiguredProject;
4748

4849
public CpsPackageReferenceProject(
4950
string projectName,
5051
string projectUniqueName,
5152
string projectFullPath,
5253
IProjectSystemCache projectSystemCache,
53-
UnconfiguredProject unconfiguredProject,
54+
VSThreading.AsyncLazy<UnconfiguredProject> unconfiguredProject,
5455
INuGetProjectServices projectServices,
5556
string projectId)
5657
: base(projectName,
@@ -269,7 +270,8 @@ public override async Task<bool> InstallPackageAsync(
269270
{
270271
// This is the "partial install" case. That is, install the package to only a subset of the frameworks
271272
// supported by this project.
272-
var conditionalService = _unconfiguredProject
273+
var unconfiguredProject = await _unconfiguredProject.GetValueAsync(token);
274+
var conditionalService = unconfiguredProject
273275
.Services
274276
.ExportProvider
275277
.GetExportedValue<IConditionalPackageReferencesService>();
@@ -315,7 +317,8 @@ await SetPackagePropertyValueAsync(
315317
else
316318
{
317319
// Install the package to all frameworks.
318-
var configuredProject = await _unconfiguredProject.GetSuggestedConfiguredProjectAsync();
320+
var unconfiguredProject = await _unconfiguredProject.GetValueAsync(token);
321+
var configuredProject = await unconfiguredProject.GetSuggestedConfiguredProjectAsync();
319322

320323
var result = await configuredProject
321324
.Services
@@ -367,7 +370,8 @@ public override async Task<bool> UninstallPackageAsync(string packageId, BuildIn
367370

368371
if (installationContext.SuccessfulFrameworks.Any() && installationContext.UnsuccessfulFrameworks.Any())
369372
{
370-
var conditionalService = _unconfiguredProject
373+
var unconfiguredProject = await _unconfiguredProject.GetValueAsync(token);
374+
var conditionalService = unconfiguredProject
371375
.Services
372376
.ExportProvider
373377
.GetExportedValue<IConditionalPackageReferencesService>();
@@ -387,7 +391,8 @@ public override async Task<bool> UninstallPackageAsync(string packageId, BuildIn
387391
}
388392
else
389393
{
390-
var configuredProject = await _unconfiguredProject.GetSuggestedConfiguredProjectAsync();
394+
var unconfiguredProject = await _unconfiguredProject.GetValueAsync(token);
395+
var configuredProject = await unconfiguredProject.GetSuggestedConfiguredProjectAsync();
391396

392397
await configuredProject?.Services.PackageReferences.RemoveAsync(packageId);
393398
}

src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/CpsPackageReferenceProjectProvider.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.VisualStudio.ProjectSystem;
1010
using Microsoft.VisualStudio.ProjectSystem.Properties;
1111
using Microsoft.VisualStudio.Shell;
12+
using Microsoft.VisualStudio.Threading;
1213
using Microsoft.VisualStudio.Utilities;
1314
using NuGet.ProjectManagement;
1415
using NuGet.ProjectModel;
@@ -80,16 +81,21 @@ public NuGetProject TryCreateNuGetProject(
8081
}
8182

8283
var fullProjectPath = vsProject.FullProjectPath;
83-
var unconfiguredProject = GetUnconfiguredProject(vsProject.Project);
8484

8585
var projectServices = new CpsProjectSystemServices(vsProject, _scriptExecutor);
8686

87+
var lazyUnconfiguredProject = new AsyncLazy<UnconfiguredProject>(async () =>
88+
{
89+
await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
90+
return GetUnconfiguredProject(vsProject.Project);
91+
}, NuGetUIThreadHelper.JoinableTaskFactory);
92+
8793
return new CpsPackageReferenceProject(
8894
vsProject.ProjectName,
8995
vsProject.CustomUniqueName,
9096
fullProjectPath,
9197
_projectSystemCache,
92-
unconfiguredProject,
98+
lazyUnconfiguredProject,
9399
projectServices,
94100
vsProject.ProjectId);
95101
}

test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/CpsPackageReferenceProjectTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4421,7 +4421,6 @@ public async Task GetPackageSpecsAndAdditionalMessagesAsync_NoRestoreInfoInSolut
44214421
{
44224422
// Arrange
44234423
var projectSystemCache = new Mock<IProjectSystemCache>();
4424-
var unconfiguredProject = new Mock<UnconfiguredProject>();
44254424
var nugetProjectServices = new Mock<INuGetProjectServices>();
44264425
var projectGuid = Guid.NewGuid();
44274426
var cacheContext = new DependencyGraphCacheContext();
@@ -4432,7 +4431,7 @@ public async Task GetPackageSpecsAndAdditionalMessagesAsync_NoRestoreInfoInSolut
44324431
@"src\TestProject\TestProject.csproj",
44334432
@"c:\repo\src\TestProject\TestProject.csproj",
44344433
projectSystemCache.Object,
4435-
unconfiguredProject.Object,
4434+
unconfiguredProject: null,
44364435
nugetProjectServices.Object,
44374436
projectGuid.ToString());
44384437

test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Services/NuGetProjectManagerServiceTests.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,13 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
157157

158158
Initialize(packageSources);
159159

160-
var unconfiguredProject = new Mock<UnconfiguredProject>();
160+
var mockUnconfiguredProject = new Mock<UnconfiguredProject>();
161161
var configuredProject = new Mock<ConfiguredProject>();
162162
var projectServices = new Mock<ConfiguredProjectServices>();
163163
var packageReferencesService = new Mock<IPackageReferencesService>();
164164
var result = new Mock<IUnresolvedPackageReference>();
165165

166-
unconfiguredProject.Setup(x => x.GetSuggestedConfiguredProjectAsync())
166+
mockUnconfiguredProject.Setup(x => x.GetSuggestedConfiguredProjectAsync())
167167
.ReturnsAsync(configuredProject.Object);
168168

169169
configuredProject.SetupGet(x => x.Services)
@@ -175,6 +175,9 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
175175
packageReferencesService.Setup(x => x.AddAsync(It.IsNotNull<string>(), It.IsNotNull<string>()))
176176
.ReturnsAsync(new AddReferenceResult<IUnresolvedPackageReference>(result.Object, added: true));
177177

178+
var unconfiguredProject = new Microsoft.VisualStudio.Threading.AsyncLazy<UnconfiguredProject>(
179+
() => Task.FromResult(mockUnconfiguredProject.Object));
180+
178181
var nuGetProjectServices = new Mock<INuGetProjectServices>();
179182

180183
nuGetProjectServices.SetupGet(x => x.ScriptService)
@@ -188,7 +191,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
188191
projectUniqueName: projectFullPath,
189192
projectFullPath: projectFullPath,
190193
projectSystemCache,
191-
unconfiguredProject.Object,
194+
unconfiguredProject,
192195
nuGetProjectServices.Object,
193196
projectId);
194197

@@ -429,13 +432,13 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
429432

430433
Initialize(packageSources);
431434

432-
var unconfiguredProject = new Mock<UnconfiguredProject>();
435+
var mockUnconfiguredProject = new Mock<UnconfiguredProject>();
433436
var configuredProject = new Mock<ConfiguredProject>();
434437
var projectServices = new Mock<ConfiguredProjectServices>();
435438
var packageReferencesService = new Mock<IPackageReferencesService>();
436439
var result = new Mock<IUnresolvedPackageReference>();
437440

438-
unconfiguredProject.Setup(x => x.GetSuggestedConfiguredProjectAsync())
441+
mockUnconfiguredProject.Setup(x => x.GetSuggestedConfiguredProjectAsync())
439442
.ReturnsAsync(configuredProject.Object);
440443

441444
configuredProject.SetupGet(x => x.Services)
@@ -447,6 +450,9 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
447450
packageReferencesService.Setup(x => x.AddAsync(It.IsNotNull<string>(), It.IsNotNull<string>()))
448451
.ReturnsAsync(new AddReferenceResult<IUnresolvedPackageReference>(result.Object, added: true));
449452

453+
var unconfiguredProject = new Microsoft.VisualStudio.Threading.AsyncLazy<UnconfiguredProject>(
454+
() => Task.FromResult(mockUnconfiguredProject.Object));
455+
450456
var nuGetProjectServices = new Mock<INuGetProjectServices>();
451457

452458
nuGetProjectServices.SetupGet(x => x.ScriptService)
@@ -460,7 +466,7 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async(
460466
projectUniqueName: projectFullPath,
461467
projectFullPath: projectFullPath,
462468
projectSystemCache,
463-
unconfiguredProject.Object,
469+
unconfiguredProject,
464470
nuGetProjectServices.Object,
465471
projectId);
466472

test/TestUtilities/VisualStudio.Test.Utility/TestCpsPackageReferenceProject.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using NuGet.ProjectModel;
2323
using NuGet.Versioning;
2424
using NuGet.VisualStudio;
25+
using VSThreading = Microsoft.VisualStudio.Threading;
2526

2627
namespace Test.Utility
2728
{
@@ -51,7 +52,7 @@ private TestCpsPackageReferenceProject(
5152
string projectUniqueName,
5253
string projectFullPath,
5354
IProjectSystemCache projectSystemCache,
54-
UnconfiguredProject unconfiguredProject,
55+
VSThreading.AsyncLazy<UnconfiguredProject> unconfiguredProject,
5556
INuGetProjectServices projectServices,
5657
string projectId,
5758
string assetsFilePath,

0 commit comments

Comments
 (0)