Direct-to-S3 / Azure tus 1.0 resume IndexedDB Golden Retriever 30 locales Webcam & screen capture

Direct-to-cloud setup

CoreUpload deliberately takes no SDK dependency. You implement a small signer interface with whichever SDK you already use; the endpoints and the browser strategies do the rest. Credentials never reach the client.

1. Implement a signer

For S3 (works for MinIO, Backblaze B2, Cloudflare R2, Wasabi — anything S3-compatible):

public class MyS3Signer : IS3Signer
{
    private readonly IAmazonS3 _s3;  // your SDK, your credentials
    private const string Bucket = "my-uploads";

    public async Task<S3CreateResult> CreateMultipartUploadAsync(S3CreateRequest r, CancellationToken ct = default)
    {
        var key = $"incoming/{Guid.NewGuid()}/{r.FileName}";
        var res = await _s3.InitiateMultipartUploadAsync(Bucket, key, ct);
        return new S3CreateResult { UploadId = res.UploadId, Key = key };
    }

    public Task<S3SignResult> SignPartsAsync(S3SignRequest r, CancellationToken ct = default)
    {
        var urls = r.PartNumbers.ToDictionary(
            n => n.ToString(),
            n => _s3.GetPreSignedURL(new GetPreSignedUrlRequest {
                BucketName = Bucket, Key = r.Key, UploadId = r.UploadId,
                PartNumber = n, Verb = HttpVerb.PUT,
                Expires = DateTime.UtcNow.AddMinutes(15)
            }));
        return Task.FromResult(new S3SignResult { Urls = urls });
    }

    // CompleteMultipartUploadAsync, AbortMultipartUploadAsync,
    // and optionally ListPartsAsync (server-verified resume) follow the same shape.
}

ListPartsAsync is optional (a default interface member). Implement it and resumed sessions reconcile against what S3 actually holds instead of trusting persisted client state.

2. Register + choose the strategy

// Program.cs
builder.Services.AddSingleton<IS3Signer, MyS3Signer>();      // or IAzureSigner / IGcsSigner
app.MapCoreUploadEndpoints();   // /s3/create, /s3/sign, /s3/list-parts, /s3/complete, /s3/abort
<core-upload asp-upload-url="/api/upload/upload"
             asp-strategy="s3"
             asp-chunk-size="8MB"
             asp-chunk-concurrency="4"></core-upload>

No signer registered? The endpoints answer 501 with a clear message rather than failing mysteriously.

3. Provider cheat-sheet

Provider Interface Strategy Must-know
S3-compatible IS3Signer s3 Parts ≥ 5 MB; expose ETag in bucket CORS; lifecycle-abort stale multiparts.
Azure Blob IAzureSigner azure Short-lived SAS; blocks are invisible until PutBlockList commits.
Google Cloud Storage IGcsSigner gcs Chunks in 256 KiB multiples (aligned automatically); session URLs expire.

4. Bucket CORS (the usual blocker)

// S3 example
[{
  "AllowedOrigins": ["https://app.example.com"],
  "AllowedMethods": ["PUT", "POST"],
  "AllowedHeaders": ["*"],
  "ExposeHeaders": ["ETag"],        // multipart completion needs this
  "MaxAgeSeconds": 3600
}]