Invex.FileSystem
2.0.0-rc.23
See the version list below for details.
dotnet add package Invex.FileSystem --version 2.0.0-rc.23
NuGet\Install-Package Invex.FileSystem -Version 2.0.0-rc.23
<PackageReference Include="Invex.FileSystem" Version="2.0.0-rc.23" />
<PackageVersion Include="Invex.FileSystem" Version="2.0.0-rc.23" />
<PackageReference Include="Invex.FileSystem" />
paket add Invex.FileSystem --version 2.0.0-rc.23
#r "nuget: Invex.FileSystem, 2.0.0-rc.23"
#:package Invex.FileSystem@2.0.0-rc.23
#addin nuget:?package=Invex.FileSystem&version=2.0.0-rc.23&prerelease
#tool nuget:?package=Invex.FileSystem&version=2.0.0-rc.23&prerelease
Invex.FileSystem
A strongly-typed file system abstraction for .NET that layers build-aware path resolution and reversible file
transformations on top of System.IO.Abstractions.
Stop hard-coding paths and scattering magic strings across your build and tooling code: resolve well-known locations
by key, compose paths fluently, and make temporary, automatically-rolled-back edits to files.
Features
- Rooted paths.
RootedPathcarries its ownIFileSystem, so paths and I/O always travel together, and composes fluently with the/operator. - Keyed path resolution. Resolve locations such as
"Root"or"Artifacts"through a prioritized chain ofIPathProviderimplementations, with results cached after the first lookup. - Strongly-typed path markers. Give compile-time names to well-known paths via
IPathMarkerinstead of relying on magic strings. - Reversible file transforms.
TransformFileScopeandTransformMultiFileScopeapply temporary edits to one or many files and restore the originals on dispose, or commit them withCancelRestore(). - Dependency-injection first. A single
AddRootedFileSystem()call wires everything up; register custom providers withProvidePath(...). - Testable. Everything works against
IFileSystem, so aMockFileSystemdrops straight into your tests.
Installation
dotnet add package Invex.FileSystem
The package targets .NET 10.0. It depends on System.IO.Abstractions,
Microsoft.Extensions.DependencyInjection.Abstractions and Microsoft.Extensions.Hosting.Abstractions. The rooted file
system logs path resolutions through ILogger, so register logging (for example services.AddLogging()) in your
container. Generic-host apps already have both; a standalone console or build tool also needs the
Microsoft.Extensions.DependencyInjection and Microsoft.Extensions.Logging packages for BuildServiceProvider() and
AddLogging():
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Logging
Quick start
Register the file system with your DI container and declare where your well-known paths live:
using Invex.FileSystem;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddLogging();
// Register the rooted file system.
services.AddRootedFileSystem();
// Describe where your well-known paths live.
services.ProvidePath((key, fs) => key switch
{
"Root" => fs.CurrentDirectory,
"Artifacts" => fs.GetPath("Root") / "artifacts",
_ => null,
});
using var provider = services.BuildServiceProvider();
var fs = provider.GetRequiredService<IRootedFileSystem>();
// Resolve and compose paths.
RootedPath artifacts = fs.GetPath("Artifacts");
RootedPath logFile = artifacts / "logs" / "build.log";
if (!logFile.PathExists)
fs.Directory.CreateDirectory(artifacts);
Usage
Compose and query paths
A RootedPath binds an absolute path string to the IFileSystem it belongs to, so existence checks and queries need
no extra context. It implicitly converts to string for any API that expects one:
RootedPath path = fs.GetPath("Root") / "src" / "Project.csproj";
bool exists = path.PathExists; // file or directory
RootedPath? parent = path.Parent; // null at the root
File.ReadAllText(path);
See Rooted Paths.
Resolve well-known locations by key
IRootedFileSystem.GetPath(string) queries every registered IPathProvider in descending priority order and caches
the first non-null result. Use the (key, fs) overload of ProvidePath when a path depends on another resolved path:
services.ProvidePath((key, fs) => key == "Output"
? fs.GetPath("Root") / "output"
: null, priority: 5);
See Path Providers.
Name paths with types
Implement IPathMarker when a path is statically determined by a type. Markers bypass the provider chain and cache:
public sealed class ArtifactsPath : IPathMarker
{
public static RootedPath Path(IFileSystem fileSystem) =>
((IRootedFileSystem)fileSystem).GetPath("Root") / "artifacts";
}
RootedPath artifacts = fs.GetPath<ArtifactsPath>();
See Path Markers.
Patch files temporarily
TransformFileScope captures a file's content, applies a transform and restores the original when the scope is
disposed. TransformMultiFileScope does the same for a set of files:
await using (var scope = await TransformFileScope.CreateAsync(
fs.GetPath("Root") / "Directory.Build.props",
content => content.Replace("1.0.0", "2.0.0")))
{
// The file now contains "2.0.0"; run your build step here.
}
// On dispose the original content is restored automatically.
Test without touching the disk
Construct a RootedPath over a MockFileSystem, or override the keyed "RootedFileSystem" registration in your
container:
var mock = new MockFileSystem();
var path = new RootedPath(mock, "/repo/file.txt");
mock.AddFile(path, new MockFileData("hello"));
// path.FileExists is now true
See Testing.
Documentation
Full documentation: https://invex-games.github.io/filesystem/
| Guide | Contents |
|---|---|
| Introduction | What the library solves, when to use it, and the pieces at a glance. |
| Getting Started | Installation, DI registration, and your first resolved paths. |
| Rooted Paths | Creating, composing and querying RootedPath. |
| Path Providers | Priorities, caching, custom providers and error handling. |
| Path Markers | Strongly-typed paths with IPathMarker. |
| File Transform Scopes | Temporary, reversible single- and multi-file edits. |
| Testing | Using MockFileSystem with rooted paths and transform scopes. |
| API Reference | Every public type, with links into the generated reference. |
Development
dotnet build Invex.FileSystem.slnx
dotnet test Invex.FileSystem.slnx
The documentation site is built with DocFX through the
Atom build in _atom/:
atom BuildDocs # generate the site
atom ServeDocs # build and serve it locally
Without the atom tool installed, run the same targets with dotnet run --project _atom -- BuildDocs.
License
Licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- JetBrains.Annotations (>= 2026.2.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.13)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.13)
- System.IO.Abstractions (>= 22.3.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Invex.FileSystem:
| Package | Downloads |
|---|---|
|
Invex.Atom.Build
An opinionated task and build automation framework |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.1.0 | 32 | 10/15/2026 |
| 2.1.0-rc.2 | 30 | 10/15/2026 |
| 2.0.0 | 472 | 10/14/2026 |
| 2.0.0-rc.31 | 30 | 10/14/2026 |
| 2.0.0-rc.29 | 38 | 10/14/2026 |
| 2.0.0-rc.27 | 35 | 10/14/2026 |
| 2.0.0-rc.23 | 32 | 10/14/2026 |
| 2.0.0-rc.20 | 30 | 10/14/2026 |
| 2.0.0-rc.18 | 41 | 10/14/2026 |
| 2.0.0-rc.16 | 33 | 10/14/2026 |
| 1.5.0-rc.8 | 41 | 10/13/2026 |
| 1.5.0-rc.2 | 76 | 9/11/2026 |
| 1.4.0 | 1,395 | 8/31/2026 |
| 1.4.0-rc.8 | 79 | 8/28/2026 |
| 1.4.0-rc.6 | 79 | 8/21/2026 |
| 1.4.0-rc.4 | 89 | 8/14/2026 |
| 1.4.0-rc.2 | 76 | 8/7/2026 |
| 1.3.0 | 6,818 | 8/3/2026 |
| 1.3.0-rc.6 | 80 | 8/3/2026 |
| 1.3.0-rc.4 | 75 | 7/24/2026 |