The core of WriteableFileProviders: the
IWriteableFileProvider interface, the base class every provider builds on, and building a provider from
configuration.
You rarely install it yourself: each provider package brings it.
dotnet add package WriteableFileProviders.Physical
Or .AzureBlob, .AmazonS3, .Minio, .GoogleCloudStorage, .Box, .SharePoint. Install Common alone to write a
provider of your own. Needs .NET 10, and is native AOT compatible, except building a provider from configuration
(Native AOT). Keep every WriteableFileProviders
package in an app on the same major version.
using WriteableFileProviders;
IWriteableFileProvider files = WriteableFileProviderSerializer.FromConfiguration(configuration.GetSection("Files"));
await files.UpdateFileAsync("reports/2026.csv", stream); // creates reports/ if missing
await files.UpdateFileAsync("app.log", line, UpdateFileOptions.Append);
await using var slice = await files.ReadRangeAsync("big.bin", 1_000_000, 4096); // 4,096 bytes from 1,000,000
await foreach (var entry in files.EnumerateAsync("reports", recursive: true)) { }
await files.MoveAsync("reports/2026.csv", "archive/2026.csv"); // FileExistsException if taken
var url = await files.GetSignedUrlAsync("archive/2026.csv", new SignedUrlOptions { Validity = TimeSpan.FromMinutes(15) });Paths are relative to the provider's root, and nothing outside it can be reached. Every member is async, except the
three IFileProvider ones (GetFileInfo, GetDirectoryContents, Watch).
{ "Files": { "Type": "WriteableAzureBlobFileProvider", "AccountName": "contoso", "AccountKey": "...", "ContainerName": "files" } }| Key | Default | Meaning |
|---|---|---|
Type |
required | The provider's class name, in any case. |
RootDirectoryPath |
the store's root | The folder the provider is confined to, such as tenants/acme. |
RootDirectorySegments |
The same folder as an array of names. | |
| any other | The provider's options, by property name, in any case. Its README lists them. |
Register it with dependency injection as a singleton IWriteableFileProvider, which the container builds on first use
and disposes:
services.AddWriteableFileProvider(configuration.GetSection("Files"));For several providers, register each under a key: services.AddKeyedSingleton<IWriteableFileProvider>(key, ...).
WriteableFileProviderSerializer also reads JSON (FromJson) and writes a provider back (ToJson, ToJsonString).
The JSON holds the options' secrets: never log it. To build a provider of your own from configuration, call
WriteableFileProviderSerializer.Register<TProvider>() first, or pass its assembly.
The serializer finds types and reads options through reflection, so it warns in a trimmed or native AOT app. There, bind the options and build the provider in code:
var options = configuration.GetSection("Files").Get<AzureBlobFileProviderOptions>()!;
services.AddWriteableFileProvider(_ => new WriteableAzureBlobFileProvider(options));