Skip to content

About

One writeable IFileProvider for .NET: read, write, append, list and sign links for files on the local disk, Azure Blob Storage, Amazon S3, MinIO, Google Cloud Storage, Box and SharePoint, with the same API and the same meaning on every store. Native AOT compatible, except Google Cloud Storage and Box.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

WriteableFileProviders

NuGet CI CodeQL Licence: MIT .NET 10 Native AOT

One writeable IFileProvider for .NET, over the local disk and six cloud stores: read, write, list, move and sign links with the same code everywhere. Native AOT compatible, except Google Cloud Storage and Box.

Providers

Package Store Native AOT Downloads
Physical A folder on the local disk ✓ Downloads
AzureBlob Azure Blob Storage ✓ Downloads
AmazonS3 Amazon S3, or an S3-compatible server ✓ Downloads
Minio MinIO ✓ Downloads
GoogleCloudStorage Google Cloud Storage Downloads
Box Box Downloads
SharePoint SharePoint, through Microsoft Graph ✓ Downloads
AspNetCore Signed links for every store, served by your app ✓ Downloads
Common The interface, the base class and configuration ✓ Downloads

Each package is WriteableFileProviders.<name> on NuGet, all at the same version, and brings WriteableFileProviders.Common.

Another store? Derive from WriteableFileProvider<TOptions> in Common and implement five members. The base class handles paths, the root, conditions, copies, moves and errors (Writing a provider).

Install

dotnet add package WriteableFileProviders.AzureBlob

One package per store. Add WriteableFileProviders.AspNetCore for signed links on every store. .NET 10 only; on .NET 8, stay on 2026.10.10.x: it is unlisted on nuget.org, so reference it by version.

The interface

public interface IWriteableFileProvider : IFileProvider, IDisposable, IAsyncDisposable
{
    // Look and list
    Task<IWriteableFileInfo> GetFileInfoAsync(ProviderPath path);
    Task<IDirectoryContents> GetDirectoryContentsAsync(ProviderPath path);
    IAsyncEnumerable<IWriteableFileInfo> EnumerateAsync(ProviderPath path, bool recursive = false);

    // Read: the whole file, a byte range, or a stream you can seek
    Task<Stream> ReadFileAsync(ProviderPath path);
    Task<Stream> ReadRangeAsync(ProviderPath path, long offset, long? length, ReadOptions? options = null);
    Task<Stream> OpenReadSeekableAsync(ProviderPath path, SeekableReadOptions? options = null);

    // Write (overwrite or append; only if unchanged, IfMatch, or absent, IfNotExists), delete, move, copy
    Task UpdateFileAsync(ProviderPath path, Stream contents, UpdateFileOptions? options = null);
    Task<bool> DeleteAsync(ProviderPath path);
    Task MoveAsync(ProviderPath source, ProviderPath destination);
    Task CopyAsync(ProviderPath source, ProviderPath destination);

    // Edit through a local copy, uploaded when it is disposed; a signed link to download or upload the file
    Task<LocalFileStream> CreateLocalFileStreamAsync(ProviderPath path, bool readOnly);
    Task<SignedUrl> GetSignedUrlAsync(ProviderPath path, SignedUrlOptions options);
}

Every member also takes a CancellationToken. A path is a ProviderPath relative to the provider's root; a string converts to one. Writes are all or nothing, no path reaches outside the root, and failures are the same few exceptions on every store. Register a provider:

builder.Services.AddWriteableFileProvider(builder.Configuration.GetSection("Files"));
{ "Files": { "Type": "WriteableAzureBlobFileProvider", "AccountName": "contoso", "ContainerName": "files",
             "UseDefaultAzureCredential": true } }

Then inject IWriteableFileProvider wherever you need files. Another store is another configuration, not new code.

Native AOT

Every package works in trimmed and native AOT apps except GoogleCloudStorage and Box, whose SDKs read and write JSON through reflection. CI publishes an app over the others with native AOT and runs it: on the local disk, Azurite, MinIO and an in-memory Microsoft Graph.

Building a provider from configuration by its Type uses reflection too, so AddWriteableFileProvider(section) and WriteableFileProviderSerializer warn in an AOT app. Bind the options and build the provider in code instead:

var options = builder.Configuration.GetSection("Files").Get<AzureBlobFileProviderOptions>()!;
builder.Services.AddWriteableFileProvider(_ => new WriteableAzureBlobFileProvider(options));

In an ASP.NET Core AOT app, SharePoint adds one warning, IL2104 for Microsoft.IO.RecyclableMemoryStream, which Microsoft Graph uses. It is harmless: that package's event logging passes only primitives.

Signed links

GetSignedUrlAsync returns the store's own link where it has one: an Azure SAS, an S3 or MinIO presigned URL, a Google Cloud Storage V4 URL. Elsewhere, the gateway in WriteableFileProviders.AspNetCore serves it from your app, and IWriteableFileUrlService picks the right one (Signed URLs).

Learn more

Versioning

All packages ship together at one SemVer version: use the same version of each. 2027.x adds features and fixes; 2028.0.0 is the next breaking release. The major is a sequence number, not a date (policy).

Contributing

Issues and pull requests are welcome: see CONTRIBUTING.md, and AGENTS.md for the rules.

Security

Report vulnerabilities privately, never in an issue: see SECURITY.md.

Licence

MIT. Copyright (c) 2018-2026 the WriteableFileProviders contributors.

About

One writeable IFileProvider for .NET: read, write, append, list and sign links for files on the local disk, Azure Blob Storage, Amazon S3, MinIO, Google Cloud Storage, Box and SharePoint, with the same API and the same meaning on every store. Native AOT compatible, except Google Cloud Storage and Box.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages