Decode.Storage.FileSystem
2.0.0
See the version list below for details.
dotnet add package Decode.Storage.FileSystem --version 2.0.0
NuGet\Install-Package Decode.Storage.FileSystem -Version 2.0.0
<PackageReference Include="Decode.Storage.FileSystem" Version="2.0.0" />
<PackageVersion Include="Decode.Storage.FileSystem" Version="2.0.0" />
<PackageReference Include="Decode.Storage.FileSystem" />
paket add Decode.Storage.FileSystem --version 2.0.0
#r "nuget: Decode.Storage.FileSystem, 2.0.0"
#:package Decode.Storage.FileSystem@2.0.0
#addin nuget:?package=Decode.Storage.FileSystem&version=2.0.0
#tool nuget:?package=Decode.Storage.FileSystem&version=2.0.0
Decode.Storage.FileSystem
Local FileSystem storage implementation of IStorageService for the Decode.Storage ecosystem.
📦 Installation
dotnet add package Decode.Storage.FileSystem
🛠️ Usage
1. Register Services
In your Program.cs or Startup.cs:
using Decode.Storage.FileSystem.Extensions;
builder.Services.AddFileSystemStorage(options =>
{
options.BasePath = "C:\\StorageRoot"; // Or load from configuration
});
This registration automatically registers IFileValidator (implemented by FileSignatureValidator) as a singleton in your dependency injection container.
2. Inject and Use in Services
using Decode.Storage.Abstractions;
public class DocumentService
{
private readonly IStorageService _storage;
public DocumentService(IStorageService storage)
{
_storage = storage;
}
public async Task SaveReportAsync(string fileName, Stream content)
{
// Writes to a temporary file first, then moves it into place with overwrite in a single
// operation, so readers never observe a partially written or momentarily missing file.
string savedPath = await _storage.UploadAsync($"reports/{fileName}", content, "application/pdf");
}
public async Task<StorageFile?> GetReportAsync(string fileName)
{
// Safe streaming and reading
return await _storage.DownloadAsync($"reports/{fileName}");
}
}
🔒 Path Containment (changed in 2.0.0)
Every path is resolved against BasePath and verified to stay inside it. Paths that are rooted, or
that resolve outside the base directory, are rejected with ArgumentException:
await _storage.UploadAsync("reports/2026/q1.pdf", content); // ok
await _storage.UploadAsync("../../etc/passwd", content); // ArgumentException
await _storage.UploadAsync(@"C:\Windows\System32\x.dll", content); // ArgumentException
Versions before 2.0.0 sanitized by stripping ".." substrings and then called
Path.Combine(basePath, cleanPath). Path.Combine discards its first argument when the second is
rooted, so any absolute path escaped the storage root entirely — arbitrary read, write and delete
across the filesystem. The substring stripping was also lossy: a legitimate name like
report..v2.pdf was silently rewritten to reportv2.pdf.
Both are fixed: containment is now proven by canonicalizing the resolved path, and file names are never rewritten.
Note on
GetUrlAsync. It returns afile://URI containing the absolute server path. That leaks your directory layout if handed to a client — treat it as internal-only.
📄 License
MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Decode.Storage.Abstractions (>= 2.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
-
net8.0
- Decode.Storage.Abstractions (>= 2.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
-
net9.0
- Decode.Storage.Abstractions (>= 2.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.