Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 2, 2025

Implementation of PR #13244 with Feedback Adjustments

This PR implements the IFileSystemService abstraction for temporary file/directory management across Aspire, addressing feedback from the original PR #13244.

✅ Completed Work

Core API Implementation

  • Created IFileSystemService and FileSystemService with simplified experimental API
  • API Design: CreateTempFile(string? fileName = null) - optional fileName parameter for named temp files
  • API Design: CreateTempSubdirectory(prefix?) for creating temp directories
  • Added FileSystemService property to IDistributedApplicationBuilder
  • Documentation Fix: Removed misleading configuration override docs (ASPIRE_TEMP_FOLDER, Aspire:TempDirectory)
  • XML Doc Fix: Corrected invalid cref syntax in documentation comments
  • Registered and exposed IFileSystemService in DistributedApplicationBuilder
  • Updated AspireStore to use simplified IFileSystemService.CreateTempFile()
  • Updated Locations (DCP) to use IFileSystemService
  • Test Fixes: Fixed all test compilation errors
    • Added experimental warning suppressions
    • Fixed constructor calls for AspireStore and Locations
    • Renamed shared test helper from TempDirectory to TestTempDirectory to avoid naming conflict
    • Removed aliases since shared class is now properly named

High Priority Core Files - Complete

  • PipelineOutputService.cs - Updated to use IFileSystemService instead of IConfiguration
  • DashboardEventHandlers.cs - Injected IFileSystemService, replaced Path.GetTempFileName() calls
  • ProjectResource.cs - Updated to get IFileSystemService from service provider
  • ContainerResourceBuilderExtensions.cs - Updated to use builder.ApplicationBuilder.FileSystemService

📋 Remaining Work (See IMPLEMENTATION_STATUS.md)

Integration Files:

  • Azure: AzurePublishingContext.cs, BicepProvisioner.cs
  • MAUI: MauiAndroidEnvironmentAnnotation.cs, MauiiOSEnvironmentAnnotation.cs, MauiEnvironmentHelper.cs
  • MySQL: MySqlBuilderExtensions.cs
  • UserSecretsManagerFactory.cs (add cleanup)

Testing:

  • DistributedApplicationTestingBuilder.cs
  • Create FileSystemServiceTests.cs with comprehensive coverage

Documentation:

  • Create docs/temp-folder-inventory.md with corrected line numbers

🎯 Key Improvements Over Original PR

  1. Flexible API: CreateTempFile(string? fileName = null) supports both random and named temp files
  2. Accurate documentation: Removed unimplemented configuration features
  3. Smart cleanup: When fileName is provided, automatically cleans up parent directory on dispose
  4. Fixed XML doc syntax: Corrected invalid cref references
  5. All tests compile: Fixed constructor calls and naming conflicts
  6. Clean test helpers: Renamed test TempDirectory to TestTempDirectory to avoid confusion
  7. High priority complete: All core hosting files updated
  8. Established pattern: IMPLEMENTATION_STATUS.md documents approach for remaining files

📝 Notes

  • The pattern of calling .Path and not disposing is intentional - many temp files persist for app lifetime
  • CreateTempFile() creates a simple temp file using Path.GetTempFileName()
  • CreateTempFile("filename.ext") creates a temp subdirectory with the named file inside, cleans up both on dispose
  • CreateTempSubdirectory(prefix) creates a temp directory that can be disposed for cleanup
  • All APIs are marked [Experimental("ASPIREFILESYSTEM001")]
  • Test shared helper class renamed from TempDirectory to TestTempDirectory to avoid conflict with Aspire.Hosting.TempDirectory
  • See IMPLEMENTATION_STATUS.md for detailed implementation guidance
Original prompt

Open a new PR with the contents from #13244 with adjustments based on the PR feedback.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Update PR with adjustments based on feedback Add IFileSystemService abstraction for temp file management with API improvements Dec 2, 2025
Copilot AI requested a review from davidfowl December 2, 2025 05:51
Copilot finished work on behalf of davidfowl December 2, 2025 05:51
Comment on lines 113 to 114
/// Deletes the temporary file. When created via <see cref="ITempFileSystemService.CreateTempFile(string, string)"/>,
/// also deletes the parent directory.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this isn't correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1f75f9a. The issue was invalid XML doc syntax - <see cref="ITempFileSystemService.CreateTempFile(string, string)"/> doesn't work for referencing overloaded methods. Changed to descriptive text: "When created with a specific file name in a temporary directory, also deletes the parent directory." Also fixed an unrelated backslash escape error on line 47.

Copilot finished work on behalf of davidfowl December 2, 2025 06:22
Copilot AI requested a review from davidfowl December 2, 2025 06:22
}

/// <inheritdoc/>
public TempFile CreateTempFile(string prefix, string fileName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot We just make this CreateTempFile that takes no arguments. Also remove the other overload.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified in ea082bc. Removed both overloads and replaced with single CreateTempFile() method that takes no parameters. Updated AspireStore.cs to use the simplified API.

Copilot AI changed the title Add IFileSystemService abstraction for temp file management with API improvements Add IFileSystemService abstraction for simplified temp file management Dec 2, 2025
Copilot AI requested a review from davidfowl December 2, 2025 07:42
Copilot finished work on behalf of davidfowl December 2, 2025 07:42
@davidfowl
Copy link
Member

@copilot Check failure on line 450 in tests\Aspire.Hosting.Tests\PublishAsDockerfileTests.cs

@azure-pipelines
azure-pipelines
/ dotnet.aspire (Build Windows)
tests\Aspire.Hosting.Tests\PublishAsDockerfileTests.cs#L450

tests\Aspire.Hosting.Tests\PublishAsDockerfileTests.cs(450,20): error ASPIREFILESYSTEM001: (NETCORE_ENGINEERING_TELEMETRY=Build) 'Aspire.Hosting.TempDirectory' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. (https://aka.ms/aspire/diagnostics/ASPIREFILESYSTEM001)
Check failure on line 126 in tests\Aspire.Hosting.Tests\AspireStoreTests.cs

@azure-pipelines
azure-pipelines
/ dotnet.aspire (Build Windows)
tests\Aspire.Hosting.Tests\AspireStoreTests.cs#L126

tests\Aspire.Hosting.Tests\AspireStoreTests.cs(126,47): error CS7036: (NETCORE_ENGINEERING_TELEMETRY=Build) There is no argument given that corresponds to the required parameter 'directoryService' of 'AspireStore.AspireStore(string, IFileSystemService)'
Check failure on line 27 in tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs

@azure-pipelines
azure-pipelines
/ dotnet.aspire (Build Windows)
tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs#L27

tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs(27,29): error CS7036: (NETCORE_ENGINEERING_TELEMETRY=Build) There is no argument given that corresponds to the required parameter 'directoryService' of 'Locations.Locations(IFileSystemService)'
Check failure on line 67 in tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs

@azure-pipelines
azure-pipelines
/ dotnet.aspire (Build Windows)
tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs#L67

tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs(67,29): error CS7036: (NETCORE_ENGINEERING_TELEMETRY=Build) There is no argument given that corresponds to the required parameter 'directoryService' of 'Locations.Locations(IFileSystemService)'
Check failure on line 116 in tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs

@azure-pipelines
azure-pipelines
/ dotnet.aspire (Build Windows)
tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs#L116

tests\Aspire.Hosting.Tests\Dcp\DcpHostNotificationTests.cs(116,29): error CS7036: (NETCORE_ENGINEERING_TELEMETRY=Build) There is no argument given that corresponds to the required parameter 'directoryService' of 'Locations.Locations(IFileSystemService)'
View more details on Azure Pipelines

Copy link
Contributor Author

Copilot AI commented Dec 2, 2025

@copilot Check failure on line 450 in tests\Aspire.Hosting.Tests\PublishAsDockerfileTests.cs

@azure-pipelines...

Fixed in 9358941. Addressed all build failures:

  • Added #pragma warning disable ASPIREFILESYSTEM001 to test files using TempDirectory
  • Fixed AspireStore constructor calls to pass IFileSystemService parameter
  • Fixed Locations constructor calls to pass IFileSystemService parameter (created helper method in DcpHostNotificationTests)
  • Resolved naming conflict between test's TempDirectory class and new Aspire.Hosting.TempDirectory by using alias TestTempDirectory = TempDirectory

Copilot finished work on behalf of davidfowl December 2, 2025 08:20
@davidfowl
Copy link
Member

@copilot Now update all of the high priorty items in IMPLEMENTATION_STATUS.md and keep it up to date with progress.

Copy link
Contributor Author

Copilot AI commented Dec 2, 2025

@copilot Now update all of the high priorty items in IMPLEMENTATION_STATUS.md and keep it up to date with progress.

Completed in 624e43d. Updated all high priority files:

  • PipelineOutputService.cs: Now uses IFileSystemService instead of IConfiguration, replaced lazy temp directory
  • DashboardEventHandlers.cs: Injected IFileSystemService, replaced Path.GetTempFileName() calls
  • ProjectResource.cs: Gets IFileSystemService from service provider, uses CreateTempFile()
  • ContainerResourceBuilderExtensions.cs: Uses builder.ApplicationBuilder.FileSystemService

IMPLEMENTATION_STATUS.md updated to reflect completion of high priority items. Remaining: Azure integration files, MAUI files, MySQL, testing infrastructure, and documentation.

Copilot finished work on behalf of davidfowl December 2, 2025 08:41
@davidfowl
Copy link
Member

@copilot We should make CreateTempFile take an optional file name

Copy link
Contributor Author

Copilot AI commented Dec 2, 2025

@copilot We should make CreateTempFile take an optional file name

Implemented in 109ba23. CreateTempFile now accepts optional string? fileName = null parameter. When fileName is provided, it creates a temp subdirectory and places the named file inside, automatically cleaning up both the file and parent directory on dispose. When null, it uses Path.GetTempFileName() as before.

Copilot finished work on behalf of davidfowl December 2, 2025 16:58
@davidfowl
Copy link
Member

@copilot Rename the shared helper TempDirectory to TestTempDirectory

Copy link
Contributor Author

Copilot AI commented Dec 4, 2025

@copilot Rename the shared helper TempDirectory to TestTempDirectory

Renamed in 62749e8. The shared helper class in tests/Shared/TempDirectory.cs is now TestTempDirectory, and removed the alias declarations from the three test files that were using it (PublishAsDockerfileTests.cs, MSBuildTests.cs, ResourceContainerImageBuilderTests.cs).

Copilot finished work on behalf of davidfowl December 4, 2025 09:12
@github-actions
Copy link
Contributor

github-actions bot commented Dec 5, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 13282

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 13282"

Copilot AI added 2 commits December 4, 2025 23:42
Co-authored-by: davidfowl <[email protected]>

Update DistributedApplicationBuilder to register and expose IFileSystemService

Co-authored-by: davidfowl <[email protected]>

Update AspireStore and Locations to use IFileSystemService

Co-authored-by: davidfowl <[email protected]>

Add implementation status document with remaining work

Co-authored-by: davidfowl <[email protected]>

Fix invalid XML doc comment syntax for TempFile.Dispose

Co-authored-by: davidfowl <[email protected]>

Simplify CreateTempFile API to take no parameters

Co-authored-by: davidfowl <[email protected]>

Fix test compilation errors - add experimental warnings and fix constructor calls

Co-authored-by: davidfowl <[email protected]>

Update high priority files to use IFileSystemService

Co-authored-by: davidfowl <[email protected]>

Add optional fileName parameter to CreateTempFile

Co-authored-by: davidfowl <[email protected]>

Rename shared TempDirectory helper class to TestTempDirectory

Co-authored-by: davidfowl <[email protected]>

Refactor file handling to use IFileSystemService for temporary file management in Maui environment annotations and MySql builder extensions

Update implementation status to reflect IFileSystemService integration across MySQL and MAUI components
@davidfowl davidfowl force-pushed the copilot/adjustments-from-pr-feedback branch from c9322e9 to 8f3fcdf Compare December 5, 2025 07:42
- Updated multiple test files across MySql, PostgreSQL, Python, and Yarp tests to replace instances of TempDirectory with TestTempDirectory for improved test isolation and resource management.
- Ensured consistent usage of TestTempDirectory in various test scenarios, including configuration file generation and environment variable handling.
@davidfowl davidfowl marked this pull request as ready for review December 5, 2025 23:43
@davidfowl davidfowl requested a review from radical as a code owner December 5, 2025 23:43
Copilot AI review requested due to automatic review settings December 5, 2025 23:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements the IFileSystemService abstraction to provide centralized temporary file and directory management across Aspire, replacing direct calls to Path.GetTempFileName() and Directory.CreateTempSubdirectory(). The implementation is marked experimental and enables better testability and consistent temp file handling.

Key Changes:

  • New IFileSystemService API with CreateTempFile() and CreateTempSubdirectory() methods
  • Integration into DistributedApplicationBuilder with DI registration
  • Migration of core components (PipelineOutputService, DashboardEventHandlers, Locations, AspireStore, etc.)
  • Refactored UserSecretsManagerFactory to accept IFileSystemService as dependency
  • Test renaming from TempDirectory to TestTempDirectory to avoid naming conflicts
  • Comprehensive test coverage in new FileSystemServiceTests.cs

Reviewed changes

Copilot reviewed 60 out of 60 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Aspire.Hosting/Utils/IFileSystemService.cs New experimental API for file system operations with temp file/directory management
src/Aspire.Hosting/Utils/FileSystemService.cs Default implementation with proper cleanup semantics
src/Aspire.Hosting/IDistributedApplicationBuilder.cs Added FileSystemService and UserSecretsManager properties (with minor doc issues)
src/Aspire.Hosting/DistributedApplicationBuilder.cs Service registration and initialization
src/Aspire.Hosting/Pipelines/PipelineOutputService.cs Migrated from IConfiguration-based temp dir to IFileSystemService
src/Aspire.Hosting/Dashboard/DashboardEventHandlers.cs Updated to use IFileSystemService for runtime config files
src/Aspire.Hosting/Dcp/Locations.cs Refactored to use IFileSystemService for DCP session directories
src/Aspire.Hosting/ApplicationModel/AspireStore.cs Updated constructor to accept IFileSystemService
src/Aspire.Hosting/ApplicationModel/ProjectResource.cs Uses IFileSystemService for Dockerfile generation
src/Aspire.Hosting/ContainerResourceBuilderExtensions.cs Uses builder.ApplicationBuilder.FileSystemService for temp files
src/Aspire.Hosting/UserSecrets/* Refactored to use IFileSystemService, removed singleton pattern
src/Aspire.Hosting/ParameterResourceBuilderExtensions.cs Updated to use builder.UserSecretsManager instead of assembly-based approach
src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs Exposed new properties for testing scenarios
src/Aspire.Hosting.MySql/MySqlBuilderExtensions.cs Updated PhpMyAdmin config file creation
src/Aspire.Hosting.Maui/Utilities/* Updated environment annotation subscribers to use IFileSystemService
src/Aspire.Hosting.Azure/* Updated BicepProvisioner and AzurePublishingContext for temp bicep files
tests/Shared/TempDirectory.cs Renamed to TestTempDirectory to avoid naming conflict
tests/**/FileSystemServiceTests.cs New comprehensive test coverage for IFileSystemService
All test files Updated to use TestTempDirectory, added experimental pragmas, fixed constructor calls

/// </para>
/// </remarks>
[Experimental("ASPIREUSERSECRETS001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
public IUserSecretsManager UserSecretsManager => throw new NotImplementedException();
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property has a default interface implementation that throws NotImplementedException. While this is intended to force implementations to override it, this could be confusing and may break consumers who try to call it on the interface directly. Consider documenting this behavior clearly or using a different pattern.

According to the custom guideline for XML Documentation Standards, default interface implementations should be clearly documented with remarks about their behavior.

Copilot generated this review using guidance from repository custom instructions.

_outputPath = options.Value.OutputPath is not null ? Path.GetFullPath(options.Value.OutputPath) : null;
_tempDirectory = new Lazy<string>(() => CreateTempDirectory(configuration));
_tempDirectory = directoryService.TempDirectory.CreateTempSubdirectory("aspire-pipelines").Path;
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The temp directory created here is stored but never disposed, which means it will persist until the process ends. This is likely intentional for the lifetime of PipelineOutputService, but the pattern doesn't match the dispose semantics described in the API documentation.

Consider documenting this pattern more explicitly, or ensuring the temp directory is cleaned up when the service is disposed (if it implements IDisposable).

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets keep the lazy implementation.

/// </summary>
/// <remarks>
/// <para>
/// The <see cref="FileSystemService"/> provides a centralized way to manage temporary files and directories
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XML documentation refers to <see cref="FileSystemService"/> but this is an implementation class, not the property type. The property returns IFileSystemService. Change the reference to match the actual return type.

Suggested fix:

/// <para>
/// The <see cref="IFileSystemService"/> provides a centralized way to manage temporary files and directories

Copilot generated this review using guidance from repository custom instructions.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="UserSecretsManager"/> provides a centralized way to manage user secrets
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XML documentation refers to <see cref="UserSecretsManager"/> but this is an implementation class, not the interface. The property returns IUserSecretsManager. Change the reference to match the actual return type.

Suggested fix:

/// <para>
/// The <see cref="IUserSecretsManager"/> provides a centralized way to manage user secrets

Copilot generated this review using guidance from repository custom instructions.
/// </para>
/// </remarks>
[Experimental("ASPIREFILESYSTEM001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
public IFileSystemService FileSystemService => throw new NotImplementedException();
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property has a default interface implementation that throws NotImplementedException. While this is intended to force implementations to override it, this could be confusing and may break consumers who try to call it on the interface directly. Consider documenting this behavior clearly or using a different pattern.

According to the custom guideline for XML Documentation Standards, default interface implementations should be clearly documented with remarks about their behavior.

Copilot generated this review using guidance from repository custom instructions.
@mitchdenny
Copy link
Member

This is good overall I think. The one thing we should think about adding is a list of allocated temporary files/directories. When a file is disposed it should remove itself from that list - but the idea is that when the apphost is shutting down we can quickly spin over the list and delete any files.

Probably also want an environment varaible that the file system service uses to preserve files for debugging scenarios.

The file system service also needs verbose logging when allocating files/directories as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants