Original author: Jay Krishna Reddy
Original link: https://www.c-sharpcorner.com/article/upload-and-download-multiple-files-using-web-api/
Translation: Desert End Wolf (with Google Translate support, upgraded to .NET 6 in the article)
---Start of article---
Today, we will introduce uploading and downloading multiple files using ASP.NET Core 6.0 Web API through a simple process.
Steps
First, create an empty Web API project in Visual Studio and select .NET 6.0 as the target framework.
No external packages are used in this project.
Create a Services folder and within it create a FileService class and an IFileService interface.
We use three methods in this FileService.cs:
UploadFileDownloadFileSizeConverter
Since we need a folder to store these uploaded files, we add a parameter here to pass the folder name as a string; it will store all uploaded files in that folder.
FileService.cs
using System.IO.Compression;
namespace FileUploadAndDownload.Services;
public class FileService : IFileService
{
#region Property
private readonly IWebHostEnvironment _webHostEnvironment;
#endregion
#region Constructor
public FileService(IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment = webHostEnvironment;
}
#endregion
#region Upload File
public void UploadFile(List<IFormFile> files, string subDirectory)
{
subDirectory = subDirectory ?? string.Empty;
var target = Path.Combine(_webHostEnvironment.ContentRootPath, subDirectory);
Directory.CreateDirectory(target);
files.ForEach(async file =>
{
if (file.Length <= 0) return;
var filePath = Path.Combine(target, file.FileName);
await using var stream = new FileStream(filePath, FileMode.Create);
await file.CopyToAsync(stream);
});
}
#endregion
#region Download File
public (string fileType, byte[] archiveData, string archiveName) DownloadFiles(string subDirectory)
{
var zipName = $"archive-{DateTime.Now:yyyy_MM_dd-HH_mm_ss}.zip";
var files = Directory.GetFiles(Path.Combine(_webHostEnvironment.ContentRootPath, subDirectory)).ToList();
using var memoryStream = new MemoryStream();
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
files.ForEach(file =>
{
var theFile = archive.CreateEntry(Path.GetFileName(file));
using var binaryWriter = new BinaryWriter(theFile.Open());
binaryWriter.Write(File.ReadAllBytes(file));
});
}
return ("application/zip", memoryStream.ToArray(), zipName);
}
#endregion
#region Size Converter
public string SizeConverter(long bytes)
{
var fileSize = new decimal(bytes);
var kilobyte = new decimal(1024);
var megabyte = new decimal(1024 * 1024);
var gigabyte = new decimal(1024 * 1024 * 1024);
return fileSize switch
{
_ when fileSize < kilobyte => "Less then 1KB",
_ when fileSize < megabyte =>
$"{Math.Round(fileSize / kilobyte, 0, MidpointRounding.AwayFromZero):##,###.##}KB",
_ when fileSize < gigabyte =>
$"{Math.Round(fileSize / megabyte, 2, MidpointRounding.AwayFromZero):##,###.##}MB",
_ when fileSize >= gigabyte =>
$"{Math.Round(fileSize / gigabyte, 2, MidpointRounding.AwayFromZero):##,###.##}GB",
_ => "n/a"
};
}
#endregion
}
The SizeConverter function is used to obtain the actual size of the files we upload to the server.
IFileService.cs
namespace FileUploadAndDownload.Services;
public interface IFileService
{
void UploadFile(List<IFormFile> files, string subDirectory);
(string fileType, byte[] archiveData, string archiveName) DownloadFiles(string subDirectory);
string SizeConverter(long bytes);
}
Let's add this service dependency in the Program.cs file.
Program.cs
using FileUploadAndDownload.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Mainly add the line below to inject the file service
builder.Services.AddTransient<IFileService, FileService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Create a FileController and inject IFileService into its constructor.
FileController.cs
using FileUploadAndDownload.Services;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
namespace FileUploadAndDownload.Controllers;
[Route("api/[controller]")]
[ApiController]
public class FileController : ControllerBase
{
private readonly IFileService _fileService;
public FileController(IFileService fileService)
{
_fileService = fileService;
}
[HttpPost(nameof(Upload))]
public IActionResult Upload([Required] List<IFormFile> formFiles, [Required] string subDirectory)
{
try
{
_fileService.UploadFile(formFiles, subDirectory);
return Ok(new { formFiles.Count, Size = _fileService.SizeConverter(formFiles.Sum(f => f.Length)) });
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
[HttpGet(nameof(Download))]
public IActionResult Download([Required] string subDirectory)
{
try
{
var (fileType, archiveData, archiveName) = _fileService.DownloadFiles(subDirectory);
return File(archiveData, fileType, archiveName);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
We can test our API in both swagger and postman.

Here we see the two APIs we created for upload and download, so let's test each of them.

Enter the folder name in the subDirectory field, and add files below to be saved in the corresponding subdirectory on the server. As a response, we will see the total number of files and the total actual size of all uploaded files.

Now let's check the download API. Since we have multiple files in our folder, it will be downloaded as a Zip file, which we need to extract to inspect the files.

Summary
Uploading and downloading files via Web API is suitable for client applications such as Blazor Server, Blazor Client, MAUI, Winform, WPF, etc. Later, when time permits, we will write about how clients call these interfaces.
- Source code: FileUploadAndDownload
.... Keep Learning!!!