KillaCore.Blazor.FileUpload
1.0.3
See the version list below for details.
dotnet add package KillaCore.Blazor.FileUpload --version 1.0.3
NuGet\Install-Package KillaCore.Blazor.FileUpload -Version 1.0.3
<PackageReference Include="KillaCore.Blazor.FileUpload" Version="1.0.3" />
<PackageVersion Include="KillaCore.Blazor.FileUpload" Version="1.0.3" />
<PackageReference Include="KillaCore.Blazor.FileUpload" />
paket add KillaCore.Blazor.FileUpload --version 1.0.3
#r "nuget: KillaCore.Blazor.FileUpload, 1.0.3"
#:package KillaCore.Blazor.FileUpload@1.0.3
#addin nuget:?package=KillaCore.Blazor.FileUpload&version=1.0.3
#tool nuget:?package=KillaCore.Blazor.FileUpload&version=1.0.3
KillaCore.Blazor.FileUpload
A robust, secure, and high-performance file upload solution for Blazor Server and Interactive Server applications. This library implements a Producer-Consumer pipeline to handle high-concurrency uploads while strictly separating network-bound operations (uploading) from CPU-bound operations (hashing, verification, and saving).
🚀 Key Features
- Pipeline Architecture: Decouples network I/O from file processing using
System.Threading.Channels. * Smart Concurrency: Configurable independent limits for concurrent network uploads vs. concurrent CPU processors. - End-to-End Security:
- HMAC SHA-256 Signed Tokens: Prevents unauthorized API access and replay attacks.
- Data Protection: Encrypts file validation rules (MIME types) so they cannot be tampered with on the client.
- Magic Number Inspection: Server-side validation of file content headers (not just file extensions).
- Resiliency: Full support for
CancellationTokenpropagation. Cancelling a batch immediately stops network requests, hashing operations, and database calls. - Lifecycle Management: Tracks file states through
Pending$\rightarrow$Uploading$\rightarrow$Hashing$\rightarrow$Verifying$\rightarrow$Saving. - Memory Efficient: Implements strict disposal patterns to clean up
CancellationTokenSourceand temporary files automatically.
📦 Installation & Setup
1. Register Services
In your Program.cs, register the file upload services. You must provide a strong secret key (min 16 characters) for the HMAC security service.
// Program.cs
using KillaCore.Blazor.FileUpload.Extension;
var builder = WebApplication.CreateBuilder(args);
// Register Blazor File Upload
// The secret key is used to sign upload tokens securely.
string uploadKey = builder.Configuration["FileUpload:SecretKey"]
?? "Your-Super-Secure-Secret-Key-Here-Min-16-Chars";
builder.Services.AddBlazorFileUpload(uploadKey);
var app = builder.Build();
2. Map Controllers
Ensure your backend is set up to map controllers. The extension automatically registers the UploadsController assembly, but you must map the endpoints.
app.MapControllers();
3. IIS / Reverse Proxy Configuration
By default, ASP.NET Core limits request bodies to ~30MB. To allow larger uploads, you must configure the request limits in web.config (if using IIS) or Kestrel.
web.config (IIS):
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="524288000" />
</requestFiltering>
</security>
💻 Usage Example
Here is a complete example of a Blazor page that handles multiple file uploads, displays a progress bar, and saves the files to disk.
@page "/upload"
@using KillaCore.Blazor.FileUpload.Components
@using KillaCore.Blazor.FileUpload.Models
@using System.IO
<h3>Secure File Processor</h3>
<div class="mb-3">
<InputFile id="myFileInput" OnChange="HandleInputOnChange" multiple class="form-control" />
</div>
<div class="mb-3">
<button class="btn btn-danger" @onclick="CancelAll" disabled="@(!_isUploading)">
Cancel All
</button>
</div>
@foreach (var file in _processor?.Transfers ?? Enumerable.Empty<FileTransferData>())
{
<div class="card mb-2">
<div class="card-body p-2">
<div class="d-flex justify-content-between">
<span>@file.FileName (@(file.FileSize / 1024) KB)</span>
<span>@file.Status - @file.StageProgressPercent.ToString("F0")%</span>
</div>
<div class="progress" style="height: 5px;">
<div class="progress-bar" role="progressbar"
style="width: @(file.LifecyclePercent)%"></div>
</div>
@if (file.Status == TransferStatus.Failed)
{
<small class="text-danger">Error: @file.StatusMessage</small>
}
</div>
</div>
}
<FileUploadProcessor @ref="_processor"
InputSelector="#myFileInput"
Options="_options"
UserId="@CurrentUserId"
OnEvent="HandleUploadEvent"
OnFileServerUpload="SaveFileToDisk"
OnVerifyRemoteDuplicate="CheckRemoteDuplicate"
OnFilesUploadCompleted="HandleBatchCompleted" />
@code {
private FileUploadProcessor? _processor;
private bool _isUploading => _processor?.Transfers.Any(t => !t.IsFinished) ?? false;
private string CurrentUserId = "User-123"; // Retrieve from auth state
// Configure specific limits and features
private FileProcessingOptions _options = new()
{
MaxFiles = 10,
MaxSizeFileBytes = 50 * 1024 * 1024, // 50 MB
MaxConcurrentUploads = 3, // Network throttle
MaxConcurrentProcessors = 2, // CPU throttle
EnabledFeatures = new HashSet<FileUploadFeature>
{
FileUploadFeature.VerifyRemoteDuplicates,
FileUploadFeature.SaveToServer
}
};
private async Task HandleInputOnChange(InputFileChangeEventArgs e)
{
// Pass the files to the processor to begin the pipeline
var files = e.GetMultipleFiles(_options.MaxFiles);
await _processor!.ProcessInputFiles(files);
}
private async Task CancelAll()
{
await _processor!.CancelAllAsync();
}
// Callback: Update UI when progress changes
private void HandleUploadEvent(FileNotificationEvent e)
{
StateHasChanged();
}
// Callback: Check if file exists (Optional)
// Note: Accepts CancellationToken to support immediate stopping
private async Task<bool> CheckRemoteDuplicate(FileTransferData data, CancellationToken ct)
{
// Example: Check your DB using data.DetectedHash
await Task.Delay(100, ct);
return false; // Return true to skip upload
}
// Callback: Save the file (Optional)
// The stream provides read access to the temp file on the server
private async Task SaveFileToDisk(FileTransferData data, Stream stream, CancellationToken ct)
{
var path = Path.Combine("C:\\Uploads", data.FileName);
// Use the token to ensure we stop writing if the user cancels
using var fs = new FileStream(path, FileMode.Create);
await stream.CopyToAsync(fs, ct);
}
// Callback: Fires when the entire batch is finished
private Task HandleBatchCompleted(IReadOnlyList<FileTransferData> files, string batchId)
{
Console.WriteLine($"Batch {batchId} finished. Processed {files.Count} files.");
return Task.CompletedTask;
}
}
⚙️ Configuration (FileProcessingOptions)
| Property | Default | Description |
|---|---|---|
UploadEndpointUrl |
api/uploads/temp |
The controller route for the initial raw upload. |
MaxFiles |
10 |
Maximum number of files allowed in a single batch. |
MaxSizeFileBytes |
50 MB |
Hard limit per file. Checked on Client and Server. |
AllowedMimeTypes |
Common Images/Docs | List of allowed MIME types. Sent as an encrypted policy header. |
MaxConcurrentUploads |
5 |
How many files to upload over the network simultaneously. |
MaxConcurrentProcessors |
2 |
How many files to hash/save simultaneously (CPU bound). |
EnabledFeatures |
All | Toggle VerifyLocalDuplicates, VerifyRemoteDuplicates, or SaveToServer. |
🔐 Security Architecture
This library employs a Signed Token Pattern to secure the upload endpoint.
- Token Generation: When an upload begins, the Blazor Server component generates a token containing
FileId,UserId,Expiration, and aHMACSHA256signature. - Encrypted Policy: The allowed MIME types are encrypted server-side using
IDataProtectionProviderand sent to the client. The client echoes this back to the API, ensuring the user cannot tamper with allowed file types in JavaScript. - API Validation: The
UploadsControllervalidates the token signature and decrypts the policy before accepting any bytes. - Content Inspection: The server inspects the file's "Magic Numbers" (file signature) to verify the actual content matches the extension.
🏗️ Architecture
The FileUploadProcessor handles files in two distinct stages to optimize server resources:
Stage 1: Network Producer
- Uploads files to a temporary location via
UploadsController. - Concurrency is limited by
MaxConcurrentUploadsto prevent saturating the bandwidth. - Pushes successful upload tokens to a
Channel<ProcessingJob>.
- Uploads files to a temporary location via
Stage 2: CPU Consumer
- Reads from the Channel.
- Claims the temporary file from the
FileUploadBridgeService. - Calculates SHA-256 Hash (CPU intensive).
- Executes the
OnFileUploadCompletedcallback. - Concurrency is limited by
MaxConcurrentProcessorsto prevent thread starvation.
📄 License
MIT License. See LICENSE.txt for more information.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- FileSignatures (>= 6.1.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.3.1 | 90 | 5/5/2026 |
| 1.3.0 | 89 | 5/5/2026 |
| 1.2.0 | 90 | 5/5/2026 |
| 1.1.3 | 94 | 5/4/2026 |
| 1.1.2 | 85 | 5/4/2026 |
| 1.1.1 | 108 | 4/7/2026 |
| 1.1.0 | 112 | 4/1/2026 |
| 1.0.12 | 164 | 1/8/2026 |
| 1.0.11 | 140 | 1/5/2026 |
| 1.0.10 | 207 | 11/25/2025 |
| 1.0.9 | 200 | 11/25/2025 |
| 1.0.8 | 197 | 11/24/2025 |
| 1.0.7 | 197 | 11/24/2025 |
| 1.0.6 | 195 | 11/24/2025 |
| 1.0.5 | 201 | 11/24/2025 |
| 1.0.4 | 199 | 11/24/2025 |
| 1.0.3 | 200 | 11/24/2025 |
| 1.0.2 | 193 | 11/24/2025 |
| 1.0.1 | 199 | 11/24/2025 |
| 1.0.0 | 203 | 11/23/2025 |