Custom Storage Provider
Implement a custom storage provider to save files to any destination: cloud storage, databases, or networked file systems.
What you should see: files stored through a provider you supply rather than the built-in filesystem one. The client side is unchanged — only the server's destination differs. Accepts up to 100 MB.
Drag & drop files here, or paste from clipboard
<core-upload asp-upload-url="/api/upload/upload"
asp-multiple="true"
asp-progress="true"
asp-auto-upload="true"
asp-max-size="100MB">
</core-upload>
<!-- Server-side: implement IStorageProvider -->
public class MyCloudStorageProvider : IStorageProvider
{
public async Task<string> SaveAsync(
Stream stream, string fileName, string contentType)
{
// Upload to your cloud storage
var blobClient = _container
.GetBlobClient(fileName);
await blobClient.UploadAsync(stream);
return blobClient.Uri.ToString();
}
public async Task DeleteAsync(string fileId)
{
var blobClient = _container
.GetBlobClient(fileId);
await blobClient.DeleteIfExistsAsync();
}
public async Task<Stream> GetAsync(string fileId)
{
var blobClient = _container
.GetBlobClient(fileId);
return await blobClient.OpenReadAsync();
}
}
// In Program.cs
builder.Services.AddCoreUpload(options =>
{
options.UseStorageProvider<MyCloudStorageProvider>();
}); Storage is an interface, not a setting
IUploaderProvider decides where bytes end up. Implement SaveAsync, AppendAsync, GetInfoAsync, OpenReadAsync, DeleteAsync and PersistAsync, register it in DI, and uploads land wherever you decide — object storage, a database, a network share. FileSystemProvider is the one that ships.
AppendAsync is the method that makes chunking work
Chunked uploads arrive as a sequence, so the provider must append rather than overwrite. A provider that treats every chunk as a fresh SaveAsync ends up with only the last one — which looks like a truncated file rather than an obvious error, and is the classic mistake when writing one of these.
FindByHashAsync is optional and has a default implementation returning null. Implement it only if you want server-side deduplication; skipping it costs nothing.