Canducci.FileUpload.FluentValidation
1.0.0.7
dotnet add package Canducci.FileUpload.FluentValidation --version 1.0.0.7
NuGet\Install-Package Canducci.FileUpload.FluentValidation -Version 1.0.0.7
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Canducci.FileUpload.FluentValidation" Version="1.0.0.7" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Canducci.FileUpload.FluentValidation" Version="1.0.0.7" />
<PackageReference Include="Canducci.FileUpload.FluentValidation" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Canducci.FileUpload.FluentValidation --version 1.0.0.7
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Canducci.FileUpload.FluentValidation, 1.0.0.7"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Canducci.FileUpload.FluentValidation@1.0.0.7
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Canducci.FileUpload.FluentValidation&version=1.0.0.7
#tool nuget:?package=Canducci.FileUpload.FluentValidation&version=1.0.0.7
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Canducci.FileUpload Ecosystem
A comprehensive file upload solution for ASP.NET Core with validation, flexible configuration, and database persistence.
Portuguese: README_PTBR.md
Overview
The Canducci.FileUpload ecosystem consists of two core packages that work together:
| Package | Version | Description |
|---|---|---|
| Canducci.FileUpload | 1.0.0.5 | Core file upload with validation, async/sync operations, and multiple filename strategies |
| Canducci.FileUpload.Database | 1.0.0.5 | Database persistence layer with automatic table creation at runtime (IHostedService) |
Both packages support .NET 8, 9, and 10.
Quick Start
1. Install Packages
# Core file upload
dotnet add package Canducci.FileUpload
# Database persistence (optional)
dotnet add package Canducci.FileUpload.Database
2. Configure Services (Program.cs)
using Canducci.FileUpload.Extensions;
using Canducci.FileUpload.Database.Extensions;
using SqlKata.Compilers;
using System.Data.SqlClient;
using MySql.Data.MySqlClient;
using Npgsql;
using Microsoft.Data.Sqlite;
using FirebirdSql.Data.FirebirdClient;
using Oracle.ManagedDataAccess.Client;
var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
// Core file upload
builder.Services.AddFileUpload(config =>
{
config.FileUploadConfigurationName = FileUploadConfigurationName.Guid;
});
// Database persistence - Choose ONE provider:
// SQL Server
builder.Services.AddFileUploadTable<long, long>(
connectionFactory: _ => new SqlConnection(configuration.GetConnectionString("SQLServer")),
compiler: new SqlServerCompiler(),
tableFields: TableFields.CreateSqlServer()
);
// PostgreSQL
builder.Services.AddFileUploadTable<long, long>(
connectionFactory: _ => new NpgsqlConnection(configuration.GetConnectionString("Postgres")),
compiler: new PostgresCompiler(),
tableFields: TableFields.CreatePostgres()
);
// SQLite
builder.Services.AddFileUploadTable<long, long>(
connectionFactory: _ => new SqliteConnection(configuration.GetConnectionString("SqLite")),
compiler: new SqliteCompiler(),
tableFields: TableFields.CreateSQLite()
);
// MySQL
builder.Services.AddFileUploadTable<long, long>(
connectionFactory: _ => new MySqlConnection(configuration.GetConnectionString("MySQL")),
compiler: new MySqlCompiler(),
tableFields: TableFields.CreateMySQL()
);
// Firebird
builder.Services.AddFileUploadTable<long, long>(
connectionFactory: _ => new FbConnection(configuration.GetConnectionString("Firebird")),
compiler: new FirebirdCompiler(),
tableFields: TableFields.CreateFirebird()
);
// Oracle
builder.Services.AddFileUploadTable<long, long>(
connectionFactory: _ => new OracleConnection(configuration.GetConnectionString("Oracle")),
compiler: new OracleCompiler(),
tableFields: TableFields.CreateOracle()
);
var app = builder.Build();
3. Use in Controller
using Canducci.FileUpload;
using Canducci.FileUpload.Database;
using Canducci.FileUpload.Enuns;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class FilesController : ControllerBase
{
[HttpPost("upload")]
public async Task<IActionResult> Upload(
IFileUpload fileUpload,
ITableFileUploadService<long, long> tableService,
CancellationToken cancellationToken)
{
var options = new FileUploadOptions(
maxFileSizeBytes: 10 * 1024 * 1024,
rejectEmptyFiles: true,
allowedExtensions: ".jpg", ".jpeg", ".png", ".pdf", ".docx");
var result = await fileUpload.SaveAsync("uploads", options, cancellationToken);
// Persist to database
if (result.Status == FileUploadStatus.AllSucceeded ||
result.Status == FileUploadStatus.PartialSuccess)
{
await tableService.ExecuteAsync(fileUpload, "uploads", options, 1, 1);
}
return result.Status switch
{
FileUploadStatus.AllSucceeded => Ok(new {
Message = "All files saved",
Count = result.SuccessCount,
Files = result.Files.Select(f => new { f.FileNameSave, f.Path })
}),
FileUploadStatus.PartialSuccess => Ok(new {
Message = "Some files saved",
Succeeded = result.SuccessCount,
Failed = result.FailureCount
}),
FileUploadStatus.AllFailed => BadRequest(new {
Message = "All files failed",
Errors = result.Files.Select(f => f.Exception?.Message)
}),
_ => BadRequest(new { Error = "No files provided" })
};
}
}
Canducci.FileUpload (Core)
Features
- Validation: File size, extension allowlist, empty file rejection
- Filename Strategies: Random, GUID, GUID v7, ULID
- Async/Sync: Full
CancellationTokensupport - Multi-file: Single or batch upload handling
- Security: Path sanitization, atomic saves, overwrite prevention
Configuration
builder.Services.AddFileUpload(config =>
{
config.FileUploadConfigurationName = FileUploadConfigurationName.Guid;
// Available: Random, Guid, GuidVersion7, Ulid (>= 1.0.0.4)
});
FileUploadOptions
// Defaults: 10MB, reject empty, no extension restrictions
var options = new FileUploadOptions();
// Parameterized constructors
var options = new FileUploadOptions(5_000_000, false); // size, rejectEmpty
var options = new FileUploadOptions(2_000_000, true, ".pdf", ".docx", ".xlsx");
// Fluent API for common extension groups
options.AllowedExtensions
.AddImages() // 10 image extensions
.AddDocuments() // 10 document extensions
.AddArchives(); // 5 archive extensions
Result Handling
var result = fileUpload.Save("uploads", options);
switch (result.Status)
{
case FileUploadStatus.AllSucceeded:
// All files saved
break;
case FileUploadStatus.PartialSuccess:
// result.SuccessCount succeeded, result.FailureCount failed
break;
case FileUploadStatus.AllFailed:
// All failed
break;
case FileUploadStatus.Empty:
// No files provided
break;
}
Canducci.FileUpload.Database
Features
- Automatic Table Creation:
IHostedServicecreates table at application startup - Multi-database: MySQL, SQL Server, Oracle, SQLite, Firebird, PostgreSQL
- Multi-tenant/User: Generic
TTenant,TUsertypes - CRUD Operations: Add, Update, Get by ID, List with filters
- SqlKata Powered: Type-safe query building
Supported Databases
// SQL Server
new SqlServerCompiler()
// MySQL
new MySqlCompiler()
// PostgreSQL
new PostgresCompiler()
// SQLite
new SqliteCompiler()
// Oracle
new OracleCompiler()
// Firebird
new FirebirdCompiler()
TableFields - Column Mapping
// Default (snake_case)
var fields = TableFields.Default;
// SQL Server (PascalCase)
var fields = TableFields.CreateSqlServer();
// MySQL (snake_case)
var fields = TableFields.CreateMySQL();
// PostgreSQL (UPPER_CASE)
var fields = TableFields.CreatePostgres();
// Custom
var fields = TableFields.Create(
table: "uploads",
id: "id",
tenantReference: "tenant_id",
userReference: "user_id",
extension: "ext",
fileName: "original_name",
path: "file_path",
length: "size_bytes",
createdAt: "created_at",
updateAt: "updated_at"
);
Services
| Interface | Description |
|---|---|
ITableService<TTenant, TUser> |
Low-level CRUD operations |
ITableFileUploadService<TTenant, TUser> |
High-level upload + persistence coordination |
Usage Patterns
1. Automatic Upload + Persist
[HttpPost]
public async Task<IActionResult> Upload(
IFileUpload fileUpload,
ITableFileUploadService<long, long> tableService,
CancellationToken ct)
{
var options = new FileUploadOptions(10_000_000, true, ".pdf", ".docx");
// Upload to disk AND persist to database in one call
var success = await tableService.ExecuteAsync(fileUpload, "uploads", options,
tenantId: 1, userId: 100);
return success ? Ok() : BadRequest();
}
2. Manual Persistence
var result = await fileUpload.SaveAsync("uploads", options, ct);
if (result.Status != FileUploadStatus.Empty)
{
// Persist successful files
var records = tableService.Add(result, tenantId: 1, userId: 100);
}
3. Query Records
// All records
var all = tableService.ToList();
// By tenant
var tenantFiles = tableService.ToListByTenant(tenantId: 1);
// By user
var userFiles = tableService.ToListByUser(userId: 100);
// By ID
var file = tableService.FirstOrDefault(id: 42);
Version History
| Version | Date | Changes |
|---|---|---|
| 1.0.0.0 | Initial | Core file upload |
| 1.0.0.1 | FileUploadStatus enum, SuccessCount/FailureCount | |
| 1.0.0.2 | XML docs, Data Annotations support | |
| 1.0.0.3 | Multiple constructors, Fluent API | |
| 1.0.0.4 | GUID v7, ULID filename strategies | |
| 1.0.0.5 | Database integration (TableService, TableFileUploadService, IHostedService) |
Current Stable: 1.0.0.5
Example Projects
| Project | Description |
|---|---|
WebAppTest |
Full Razor Views + Controllers demo |
WebFileUploadBasic |
Minimal basic upload |
WebFilesUploadBasic |
Multiple files handling |
WebFilesUploadBasicGuidNameGenerate |
GUID filename strategy |
WebFilesUploadBasicOnlyImages |
Image-only uploads |
WebFilesUploadBasicOnlyImagensDataAnnotation |
Data Annotations validation |
Canducci.FileUpload.FluentValidation |
FluentValidation integration |
Security
- ✅ Filename sanitization & path traversal protection
- ✅ Case-insensitive extension validation
- ✅ Overwrite prevention (unique filenames)
- ✅ Atomic saves (temp file → rename)
- ✅ CancellationToken support
- ✅ Granular per-file error handling
Requirements
- .NET 8.0 or later
- ASP.NET Core
License
MIT License
Author
Fulvio Canducci - GitHub
| 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 is compatible. 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 is compatible. 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. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- Canducci.FileUpload (>= 1.0.0.7)
- FluentValidation (>= 12.1.1)
-
net8.0
- Canducci.FileUpload (>= 1.0.0.7)
- FluentValidation (>= 12.1.1)
-
net9.0
- Canducci.FileUpload (>= 1.0.0.7)
- FluentValidation (>= 12.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.
Initial release of FluentValidation integration for Canducci.FileUpload.