· via dev.to (home feed)
SmartUpload 1.0.7 brings crash-resilient chunked uploads to .NET MAUI
Plugin.Maui.SmartUpload 1.0.7 persists every acknowledged upload offset to disk, so .NET MAUI apps can resume chunked transfers after a crash, pause, or retry instead of restarting from byte zero.

Version 1.0.7 of Plugin.Maui.SmartUpload has landed on nuget.org. According to a walkthrough on dev.to, the library is a chunked upload client for .NET MAUI whose defining feature is durability: every offset the server acknowledges is written to disk, so the next attempt — after a crash, a deliberate pause, or a retry — continues from that byte rather than starting over.
The problem it targets is familiar to anyone building mobile apps. A photo upload killed halfway through a single POST has to restart from byte zero, and a fresh app launch has no memory of what the server already received. SmartUpload keeps that memory on behalf of the app.
What is in the release
SmartUpload is MIT licensed and runs on Android, iOS, Mac Catalyst, and Windows. It targets net10.0 along with platform flavors: net10.0-android (API 21+), net10.0-ios and net10.0-maccatalyst (15+), and net10.0-windows (10.0.17763+). As the dev.to post notes, 1.0.7 specifically adds the Mac Catalyst and Windows target frameworks for the shared implementation.
One boundary the author is explicit about: the operating system stops sending bytes once the process is gone. A transfer that must keep going with the UI closed still needs the host app to provide a foreground service on Android or an NSURLSession background configuration on iOS. SmartUpload is the resume point those platform hosts call back into.
Setup and configuration
After installing the package, apps register the client with UseSmartUpload during MauiApp builder setup, passing options such as EnableLogging, DefaultChunkSize, MaxConcurrentUploads, ResumeInterruptedOnStart, RequireHttps, and a DefaultRetry policy. The client is then resolved from dependency injection or accessed via SmartUpload.Current.
Defaults worth knowing: chunk size falls back to 1 MB and is clamped between 64 KB and 32 MB; per-request chunk sizes must be positive and are capped at 32 MB. MaxConcurrentUploads defaults to 2, with extra sessions waiting in a Queued state until a slot frees up. Each chunk gets a 100-second HTTP timeout. ResumeInterruptedOnStart is false by default, so developers either enable it or call ResumeInterruptedAsync() themselves after launch to revive sessions that were mid-flight when the process died, plus any queued work flagged with AutoStart.
Sessions, states, and control
Files are enqueued through EnqueueAsync with an UploadRequest containing an absolute FilePath, a required Endpoint, headers such as Authorization, and optional metadata. AutoStart defaults to true; disabling it persists the session for a later StartAsync. A caller-supplied SessionId may use only letters, digits, hyphens, and underscores up to 128 characters, otherwise a GUID is generated.
The client exposes PauseAsync, ResumeAsync, RetryAsync, CancelAsync, and RemoveAsync. Pausing stops after the current chunk is cancelled but preserves the offset; retrying restarts a failed or cancelled session from the same acknowledged byte. Sessions move through Queued, Uploading, Paused, Completed, Failed, and Cancelled states, surfaced through events including ProgressChanged, SessionCompleted, SessionFailed, and SessionStateChanged, with progress reported as a clamped fraction of bytes uploaded.
Wire protocols and extension point
Two protocols ship built in. ContentRange is the default: each slice is sent with a Content-Range header plus X-Upload-Id, X-Chunk-Index, and X-Chunk-Count, and an optional HEAD returning Range or X-Last-Byte lets the client catch up. Tus implements the tus 1.0 flow — POST to create, HEAD for Upload-Offset, PATCH with the application/offset+octet-stream content type, and metadata carried in Upload-Metadata. Anything else goes through a custom IUploadProtocol implementation with hooks for initialization, progress queries, chunk upload, completion, and abort; initialization must be idempotent. On cancellation, a DeleteRemoteOnCancel flag can trigger a tus DELETE when the server advertises the termination extension.
Storage and security caveats
Session state lives as JSON files under FileSystem.AppDataDirectory/Plugin.Maui.SmartUpload/, each recording the file path, size, last-write timestamp, endpoint, headers, protocol state (including the tus Location), and the acknowledged offset. The folder is relocatable and the whole store is replaceable via a custom IUploadStore. Resume checks are strict: a missing file fails with UploadError.FileNotFound, and a changed length or write time fails with UploadError.FileChanged, so the client will not continue against a file that is no longer the original.
Two cautions stand out. Headers, including Authorization tokens, are persisted in that JSON — a stored bearer token is exactly what the next request sends, so tokens that can expire while the app is dead should be refreshed before resuming. And RequireHttps defaults to true, a hardening carried over from 1.0.6; http endpoints throw unless the flag is disabled, which the author recommends only for local development.
Why it matters
Mobile processes die constantly — OS eviction, a user swiping the app away, a drained battery, a flaky connection. Restarting large uploads from zero wastes bandwidth and battery, and can mean an upload never completes at all. Offset persistence is the established fix on the web, and SmartUpload brings a comparable mechanism to .NET MAUI with practical defaults, two real protocols, retry handling, and a swappable storage layer. Its candid statement that background execution still requires a platform host is the kind of precision that separates an evaluable library from a demo.
- #dotnet-maui
- #file-upload
- #nuget
- #resumable-uploads
- #mobile-dev