Canducci.FileUpload
1.0.0.4
See the version list below for details.
dotnet add package Canducci.FileUpload --version 1.0.0.4
NuGet\Install-Package Canducci.FileUpload -Version 1.0.0.4
<PackageReference Include="Canducci.FileUpload" Version="1.0.0.4" />
<PackageVersion Include="Canducci.FileUpload" Version="1.0.0.4" />
<PackageReference Include="Canducci.FileUpload" />
paket add Canducci.FileUpload --version 1.0.0.4
#r "nuget: Canducci.FileUpload, 1.0.0.4"
#:package Canducci.FileUpload@1.0.0.4
#addin nuget:?package=Canducci.FileUpload&version=1.0.0.4
#tool nuget:?package=Canducci.FileUpload&version=1.0.0.4
Canducci.FileUpload
A file upload library for ASP.NET Core with validation, flexible configuration, and support for synchronous and asynchronous operations.
Portuguese: README_PTBR.md
Version 1.0.0.4 (stable version)
What's New
FileUploadStatusenum: Replaces the ambiguousSuccessboolean property with a clear status indicatorAllSucceeded- All files were uploaded successfullyPartialSuccess- Some files succeeded, some failedAllFailed- All files failed to uploadEmpty- No files were provided
SuccessCountproperty: Returns the count of successfully uploaded filesFailureCountproperty: Returns the count of failed uploads- Complete XML documentation in English for all public APIs
FileUploadValidationAttribute: Integration with ASP.NET Core Data Annotations- Multiple
FileUploadOptionsconstructors: Different ways to initialize with various constraints - Case-insensitive extension validation: Safe extension comparison
- .NET 8, 9, and 10 support: Compatibility with multiple .NET versions
- 91 comprehensive unit tests: Complete test coverage for reliability
Installation
Package Manager
Install-Package Canducci.FileUpload
.NET CLI
dotnet add package Canducci.FileUpload
PackageReference
<PackageReference Include="Canducci.FileUpload" Version="1.0.0.3" />
Configuration
Program.cs
Add the service in Program.cs:
using Canducci.FileUpload.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add FileUpload with default configuration (random filename)
builder.Services.AddFileUpload();
// OR with custom configuration (GUID filename)
builder.Services.AddFileUpload(config =>
{
config.FileUploadConfigurationName = FileUploadConfigurationName.Guid;
});
var app = builder.Build();
Configuration Options
| Option | Description |
|---|---|
FileUploadConfigurationName.Random |
Generates random filename (default) |
FileUploadConfigurationName.Guid |
Generates GUID-based filename |
FileUploadConfigurationName.GuidVersion7 |
Generates GUID-based V7 filename (>= 1.0.0.4) |
GuidVersion7.Ulid |
Generates ULID filename (>= 1.0.0.4) |
Controller Usage
Basic Example
using Canducci.FileUpload;
using Canducci.FileUpload.Enuns;
using Canducci.FileUpload.Interfaces;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class UploadController : ControllerBase
{
[HttpPost]
public IActionResult Upload(IFileUpload fileUpload)
{
var result = fileUpload.Save("uploads", options =>
{
options.MaxFileSizeBytes = 5 * 1024 * 1024; // 5 MB
options.RejectEmptyFiles = true;
options.AllowedExtensions.Add(".jpg");
options.AllowedExtensions.Add(".png");
options.AllowedExtensions.Add(".pdf");
});
switch (result.Status)
{
case FileUploadStatus.AllSucceeded:
return Ok(new
{
Message = "Upload successful!",
SuccessCount = result.SuccessCount,
Files = result.Files.Select(f => new
{
f.FileNameSent,
f.FileNameSave,
f.Extension,
f.Length,
f.Path
})
});
case FileUploadStatus.PartialSuccess:
return Ok(new
{
Message = "Some files uploaded successfully",
SuccessCount = result.SuccessCount,
FailureCount = result.FailureCount,
Files = result.Files.Where(f => f.Success).Select(f => f.FileNameSave),
Errors = result.Files.Where(f => !f.Success).Select(f => new
{
f.FileNameSent,
Error = f.Exception?.Message
})
});
case FileUploadStatus.AllFailed:
return BadRequest(new
{
Message = "All files failed to upload",
FailureCount = result.FailureCount,
Errors = result.Files.Select(f => new
{
f.FileNameSent,
Error = f.Exception?.Message
})
});
case FileUploadStatus.Empty:
default:
return BadRequest(new { Message = "No files provided" });
}
}
}
Async Example
[HttpPost("async")]
public async Task<IActionResult> UploadAsync(IFileUpload fileUpload, CancellationToken cancellationToken)
{
var result = await fileUpload.SaveAsync("uploads", options =>
{
options.MaxFileSizeBytes = 10 * 1024 * 1024; // 10 MB
options.RejectEmptyFiles = true;
}, cancellationToken);
if (result.Status == FileUploadStatus.AllSucceeded)
{
return Ok(new { Message = "Async upload completed!", result.SuccessCount });
}
return BadRequest(new { Message = "Upload failed", result.FailureCount });
}
Multiple Files Example
[HttpPost("multiple")]
public IActionResult UploadMultiple(IFileUpload fileUpload)
{
if (fileUpload.Count == 0)
{
return BadRequest("No files uploaded");
}
var result = fileUpload.Save("documents", options =>
{
options.MaxFileSizeBytes = 20 * 1024 * 1024; // 20 MB
options.AllowedExtensions.Add(".docx");
options.AllowedExtensions.Add(".xlsx");
options.AllowedExtensions.Add(".pdf");
});
return Ok(new
{
Status = result.Status.ToString(),
TotalUploaded = fileUpload.Count,
Succeeded = result.SuccessCount,
Failed = result.FailureCount,
Files = result.Files.Where(f => f.Success).Select(f => f.FileNameSave),
Errors = result.Files.Where(f => !f.Success).Select(f => new { f.FileNameSent, Error = f.Exception?.Message })
});
}
Predefined Options Example
[HttpPost("images")]
public IActionResult UploadImages(IFileUpload fileUpload)
{
// Parameterized constructor with multiple extensions
var options = new FileUploadOptions(2 * 1024 * 1024, true, ".jpg", ".jpeg", ".png", ".gif", ".webp");
var result = fileUpload.Save("images", options);
return result.Status == FileUploadStatus.AllSucceeded
? Ok(result.Files.Select(f => f.Path))
: BadRequest($"Failed: {result.FailureCount} of {fileUpload.Count} images");
}
Fluent API Example
[HttpPost("fluent")]
public IActionResult UploadFluent(IFileUpload fileUpload)
{
var options = new FileUploadOptions();
options.AllowedExtensions
.AddImages() // All 10 image extensions
.AddDocuments() // All 10 document extensions
.AddArchives(); // All 5 archive extensions
var result = fileUpload.Save("uploads", options);
return Ok(result);
}
Data Annotations Example
using System.ComponentModel.DataAnnotations;
using Canducci.FileUpload.Attributes;
public class FileUploadModel
{
[FileUploadValidation(
MaxFileSizeBytes = 5242880,
RejectEmptyFiles = true,
AllowedExtensions = new[] { ".pdf", ".docx", ".xlsx" }
)]
public IFileUpload Files { get; set; }
}
[HttpPost("validated")]
public IActionResult ValidatedUpload(FileUploadModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var result = model.Files.Save("documents");
return Ok(result);
}
Validation Options
| Option | Type | Default | Description |
|---|---|---|---|
MaxFileSizeBytes |
long |
10485760 (10 MB) | Maximum file size in bytes |
RejectEmptyFiles |
bool |
true |
Reject empty files (0 bytes) |
AllowedExtensions |
HashSet<string> |
Empty | Allowed extensions (empty = all) |
FileUploadOptions Constructors
// Default constructor with default values
var options1 = new FileUploadOptions();
// Constructor with max size and empty file rejection
var options2 = new FileUploadOptions(5_000_000, false);
// Constructor with all constraints
var options3 = new FileUploadOptions(2_000_000, true, ".pdf", ".docx", ".xlsx");
Result Properties
IFileUploadResult
| Property | Type | Description |
|---|---|---|
Status |
FileUploadStatus |
Overall upload operation status |
SuccessCount |
int |
Number of successfully uploaded files |
FailureCount |
int |
Number of failed uploads |
Files |
IReadOnlyList<IFileItemResult> |
List of per-file results |
FileUploadStatus Enum
| Value | Description |
|---|---|
AllSucceeded |
All files were uploaded successfully |
PartialSuccess |
Some files succeeded, some failed |
AllFailed |
All files failed to upload |
Empty |
No files were provided for upload |
IFileItemResult
| Property | Type | Description |
|---|---|---|
Success |
bool |
Whether the file was saved successfully |
FileNameSent |
string |
Original filename sent by client |
FileNameSave |
string |
Filename saved on server |
Extension |
string |
File extension |
Length |
long |
File size in bytes |
Directory |
string |
Directory where file was saved |
Path |
string |
Full file path |
Exception |
Exception? |
Exception if error occurred |
Error Messages
| Message | Description |
|---|---|
File is Empty |
File is empty and RejectEmptyFiles = true |
File is TooLarge |
File exceeds MaxFileSizeBytes |
ExtensionNotAllowed |
Extension not in AllowedExtensions |
Complete Controller Example
using Canducci.FileUpload;
using Canducci.FileUpload.Enuns;
using Canducci.FileUpload.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Controllers;
[ApiController]
[Route("api/[controller]")]
public class FilesController : ControllerBase
{
[HttpPost("upload")]
[RequestSizeLimit(50 * 1024 * 1024)] // 50 MB request limit
public async Task<IActionResult> Upload(
IFileUpload fileUpload,
CancellationToken cancellationToken)
{
if (fileUpload.Count == 0)
{
return BadRequest(new { Error = "No files uploaded" });
}
// Using parameterized constructor
var options = new FileUploadOptions(
maxFileSizeBytes: 10 * 1024 * 1024,
rejectEmptyFiles: true,
allowedExtensions: ".jpg", ".jpeg", ".png", ".pdf", ".docx");
var result = await fileUpload.SaveAsync("uploads", options, cancellationToken);
return result.Status switch
{
FileUploadStatus.AllSucceeded => Ok(new
{
Message = "All files saved successfully",
Count = result.SuccessCount,
Files = result.Files.Select(f => new { f.FileNameSave, f.Path })
}),
FileUploadStatus.PartialSuccess => Ok(new
{
Message = "Some files were saved",
Succeeded = result.SuccessCount,
Failed = result.FailureCount
}),
FileUploadStatus.AllFailed => BadRequest(new
{
Message = "Failed to save all files",
Errors = result.Files.Select(f => f.Exception?.Message)
}),
_ => BadRequest(new { Error = "No files provided" })
};
}
[HttpPost("images")]
public IActionResult UploadImages(IFileUpload fileUpload)
{
var options = new FileUploadOptions();
options.AllowedExtensions.AddImages(); // All image extensions
var result = fileUpload.Save("images", options);
return result.Status == FileUploadStatus.AllSucceeded
? Ok(result.Files)
: BadRequest(result.Files.Where(f => !f.Success));
}
[HttpPost("documents")]
public IActionResult UploadDocuments(IFileUpload fileUpload)
{
var options = new FileUploadOptions(5 * 1024 * 1024, true);
options.AllowedExtensions.AddDocuments(); // All document extensions
var result = fileUpload.Save("documents", options);
return Ok(result);
}
}
Security Features
- Filename sanitization: Removes dangerous characters and handles path traversal
- Case-insensitive extension validation: Protects against case-based bypasses
- Overwrite prevention: Generates unique names using UUID or random
- Atomic save: Saves to temporary file first, then renames atomically
- CancellationToken support: Safely cancels long-running operations
- Granular error handling: Returns detailed status per file
Supported File Extensions
The library provides constants and fluent methods for common extensions:
Images (10 extensions)
.jpg, .jpeg, .png, .gif, .webp, .svg, .bmp, .tiff, .tif, .heic
Documents (10 extensions)
.pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .txt, .csv, .odt
Archives (5 extensions)
.zip, .rar, .7z, .tar, .gz
Audio/Video (5 extensions)
.mp3, .wav, .mp4, .mkv, .avi
Library Highlights
Developed with focus on:
- ✅ Security: Rigorous validation and protection against common attacks
- ✅ Performance: Async operations and streaming for large files
- ✅ Usability: Simple and intuitive API with Fluent API support
- ✅ Documentation: Complete XML comments in English
- ✅ Testing: Comprehensive 91 unit test suite
- ✅ Compatibility: Supports .NET 8, 9, and 10
What's New
FileUploadStatusenum: Replaces the ambiguousSuccessboolean property with a clear status indicatorAllSucceeded- All files were uploaded successfullyPartialSuccess- Some files succeeded, some failedAllFailed- All files failed to uploadEmpty- No files were provided
SuccessCountproperty: Returns the count of successfully uploaded filesFailureCountproperty: Returns the count of failed uploads- Complete XML documentation in English for all public APIs
Installation
Package Manager
Install-Package Canducci.FileUpload
.NET CLI
dotnet add package Canducci.FileUpload
PackageReference
<PackageReference Include="Canducci.FileUpload" Version="1.0.0.1" />
Configuration
Program.cs
Add the service in Program.cs:
using Canducci.FileUpload.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add FileUpload with default configuration (random filename)
builder.Services.AddFileUpload();
// OR with custom configuration (GUID filename)
builder.Services.AddFileUpload(config =>
{
config.FileUploadConfigurationName = FileUploadConfigurationName.Guid;
});
var app = builder.Build();
Configuration Options
| Option | Description |
|---|---|
FileUploadConfigurationName.Random |
Generates random filename (default) |
FileUploadConfigurationName.Guid |
Generates GUID-based filename |
Controller Usage
Basic Example
using Canducci.FileUpload;
using Canducci.FileUpload.Enuns;
using Canducci.FileUpload.Interfaces;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class UploadController : ControllerBase
{
[HttpPost]
public IActionResult Upload(IFileUpload fileUpload)
{
var result = fileUpload.Save("uploads", options =>
{
options.MaxFileSizeBytes = 5 * 1024 * 1024; // 5 MB
options.RejectEmptyFiles = true;
options.AllowedExtensions.Add(".jpg");
options.AllowedExtensions.Add(".png");
options.AllowedExtensions.Add(".pdf");
});
switch (result.Status)
{
case FileUploadStatus.AllSucceeded:
return Ok(new
{
Message = "Upload successful!",
SuccessCount = result.SuccessCount,
Files = result.Files.Select(f => new
{
f.FileNameSent,
f.FileNameSave,
f.Extension,
f.Length,
f.Path
})
});
case FileUploadStatus.PartialSuccess:
return Ok(new
{
Message = "Some files uploaded successfully",
SuccessCount = result.SuccessCount,
FailureCount = result.FailureCount,
Files = result.Files.Where(f => f.Success).Select(f => f.FileNameSave),
Errors = result.Files.Where(f => !f.Success).Select(f => new
{
f.FileNameSent,
Error = f.Exception?.Message
})
});
case FileUploadStatus.AllFailed:
return BadRequest(new
{
Message = "All files failed to upload",
FailureCount = result.FailureCount,
Errors = result.Files.Select(f => new
{
f.FileNameSent,
Error = f.Exception?.Message
})
});
case FileUploadStatus.Empty:
default:
return BadRequest(new { Message = "No files provided" });
}
}
}
Async Example
[HttpPost("async")]
public async Task<IActionResult> UploadAsync(IFileUpload fileUpload, CancellationToken cancellationToken)
{
var result = await fileUpload.SaveAsync("uploads", options =>
{
options.MaxFileSizeBytes = 10 * 1024 * 1024; // 10 MB
options.RejectEmptyFiles = true;
}, cancellationToken);
if (result.Status == FileUploadStatus.AllSucceeded)
{
return Ok(new { Message = "Async upload completed!", result.SuccessCount });
}
return BadRequest(new { Message = "Upload failed", result.FailureCount });
}
Multiple Files Example
[HttpPost("multiple")]
public IActionResult UploadMultiple(IFileUpload fileUpload)
{
if (fileUpload.Count == 0)
{
return BadRequest("No files uploaded");
}
var result = fileUpload.Save("documents", options =>
{
options.MaxFileSizeBytes = 20 * 1024 * 1024; // 20 MB
options.AllowedExtensions.Add(".docx");
options.AllowedExtensions.Add(".xlsx");
options.AllowedExtensions.Add(".pdf");
});
return Ok(new
{
Status = result.Status.ToString(),
TotalUploaded = fileUpload.Count,
Succeeded = result.SuccessCount,
Failed = result.FailureCount,
Files = result.Files.Where(f => f.Success).Select(f => f.FileNameSave),
Errors = result.Files.Where(f => !f.Success).Select(f => new { f.FileNameSent, Error = f.Exception?.Message })
});
}
Predefined Options Example
[HttpPost("images")]
public IActionResult UploadImages(IFileUpload fileUpload)
{
var options = new FileUploadOptions
{
MaxFileSizeBytes = 2 * 1024 * 1024, // 2 MB
RejectEmptyFiles = true
};
options.AllowedExtensions.Add(".jpg");
options.AllowedExtensions.Add(".jpeg");
options.AllowedExtensions.Add(".png");
options.AllowedExtensions.Add(".gif");
options.AllowedExtensions.Add(".webp");
var result = fileUpload.Save("images", options);
return result.Status == FileUploadStatus.AllSucceeded
? Ok(result.Files.Select(f => f.Path))
: BadRequest($"Failed: {result.FailureCount} of {fileUpload.Count} images");
}
Validation Options
| Option | Type | Default | Description |
|---|---|---|---|
MaxFileSizeBytes |
long |
10485760 (10 MB) | Maximum file size in bytes |
RejectEmptyFiles |
bool |
true |
Reject empty files (0 bytes) |
AllowedExtensions |
HashSet<string> |
Empty | Allowed extensions (empty = all allowed) |
Result Properties
IFileUploadResult
| Property | Type | Description |
|---|---|---|
Status |
FileUploadStatus |
Overall status of the upload operation |
SuccessCount |
int |
Count of files uploaded successfully |
FailureCount |
int |
Count of files that failed to upload |
Files |
IReadOnlyList<IFileItemResult> |
List of results per file |
FileUploadStatus Enum
| Value | Description |
|---|---|
AllSucceeded |
All files were uploaded successfully |
PartialSuccess |
Some files succeeded, some failed |
AllFailed |
All files failed to upload |
Empty |
No files were provided for upload |
IFileItemResult
| Property | Type | Description |
|---|---|---|
Success |
bool |
Whether the file was saved successfully |
FileNameSent |
string |
Original filename sent by client |
FileNameSave |
string |
Filename saved on server |
Extension |
string |
File extension |
Length |
long |
File size in bytes |
Directory |
string |
Directory where file was saved |
Path |
string |
Full file path |
Exception |
Exception? |
Exception if error occurred |
Error Messages
| Message | Description |
|---|---|
File is Empty |
Empty file and RejectEmptyFiles = true |
File is TooLarge |
File exceeds MaxFileSizeBytes |
ExtensionNotAllowed |
Extension not in AllowedExtensions |
Complete Controller Example
using Canducci.FileUpload;
using Canducci.FileUpload.Enuns;
using Canducci.FileUpload.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Controllers;
[ApiController]
[Route("api/[controller]")]
public class FilesController : ControllerBase
{
[HttpPost("upload")]
[RequestSizeLimit(50 * 1024 * 1024)] // 50 MB request limit
public async Task<IActionResult> Upload(
IFileUpload fileUpload,
CancellationToken cancellationToken)
{
if (fileUpload.Count == 0)
{
return BadRequest(new { Error = "No files uploaded" });
}
var result = await fileUpload.SaveAsync("uploads", options =>
{
options.MaxFileSizeBytes = 10 * 1024 * 1024;
options.RejectEmptyFiles = true;
options.AllowedExtensions.Add(".jpg");
options.AllowedExtensions.Add(".jpeg");
options.AllowedExtensions.Add(".png");
options.AllowedExtensions.Add(".pdf");
options.AllowedExtensions.Add(".docx");
}, cancellationToken);
switch (result.Status)
{
case FileUploadStatus.AllSucceeded:
return Ok(new
{
Message = "Upload completed successfully",
SuccessCount = result.SuccessCount,
Files = result.Files.Select(f => new
{
Original = f.FileNameSent,
Saved = f.FileNameSave,
Size = f.Length,
FullPath = f.Path
})
});
case FileUploadStatus.PartialSuccess:
return Ok(new
{
Message = "Some files uploaded successfully",
SuccessCount = result.SuccessCount,
FailureCount = result.FailureCount,
SuccessfulFiles = result.Files.Where(f => f.Success).Select(f => f.FileNameSave),
Errors = result.Files.Where(f => !f.Success).Select(f => new
{
File = f.FileNameSent,
Error = f.Exception?.Message ?? "Unknown error"
})
});
case FileUploadStatus.AllFailed:
return BadRequest(new
{
Message = "All files failed to upload",
FailureCount = result.FailureCount,
Errors = result.Files.Select(f => new
{
File = f.FileNameSent,
Error = f.Exception?.Message ?? "Unknown error"
})
});
case FileUploadStatus.Empty:
default:
return BadRequest(new { Error = "No files provided" });
}
}
}
Example Projects
The Web example applications are located in the Web folder of the repository. Below are the sample projects with direct GitHub links and a short description of what each demonstrates.
WebAppTest — https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/WebAppTest
- A complete sample application with UI (Razor Views) and controllers demonstrating synchronous and asynchronous upload endpoints, multiple file uploads, and the use of configuration and validation options. Use this project to see full integration in an ASP.NET Core application.
WebFileUploadBasic — https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/WebFileUploadBasic
- A minimal project demonstrating basic configuration and upload flow that saves files to disk with randomly generated names.
WebFilesUploadBasic — https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/WebFilesUploadBasic
- Demonstrates multiple file uploads and how to collect per-file results (success/failure). Useful to learn
FileUploadResultandFileItemResultusage.
- Demonstrates multiple file uploads and how to collect per-file results (success/failure). Useful to learn
WebFilesUploadBasicGuidNameGenerate — https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/WebFilesUploadBasicGuidNameGenerate
- Example that generates GUID-based filenames. Useful when avoiding collisions and maintaining unique, predictable filenames.
WebFilesUploadBasicOnlyImages — https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/WebFilesUploadBasicOnlyImages
- Demonstrates configuring
AllowedExtensionsto accept only image types (e.g.,.jpg,.png,.webp). Ideal for image-only upload scenarios.
- Demonstrates configuring
WebFilesUploadBasicOnlyImagensDataAnnotation — https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/WebFilesUploadBasicOnlyImagensDataAnnotation
- Same image-only scenario but demonstrating use of
FileUploadValidationAttributewith Data Annotations on the model for automatic binding validation.
- Same image-only scenario but demonstrating use of
Canducci.FileUpload.FluentValidation — https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/Canducci.FileUpload.FluentValidation
- An extension project integrating the popular FluentValidation library (FluentValidation.AspNetCore) to validate IFileUpload/IFileItem using fluent validator classes. Use this project to see how to enforce validation rules with FluentValidation and integrate them into the ASP.NET Core pipeline.
- Project Web - https://github.com/fulviocanducci/Canducci.FileUpload/tree/master/WebFilesUploadBasicOnlyImagesFluentValidation
Requirements
- .NET 8.0 or later
- ASP.NET Core
License
MIT License
| 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. |
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Canducci.FileUpload:
| Package | Downloads |
|---|---|
|
Canducci.FileUpload.FluentValidation
FluentValidation integration for Canducci.FileUpload. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Canducci.FileUpload