原文作者:Jay Krishna Reddy
原文链接:https://www.c-sharpcorner.com/article/upload-and-download-multiple-files-using-web-api/
翻译:沙漠尽头的狼(谷歌翻译加持,文中版本使用.NET 6升级)
---正文开始---
今天,我们将通过一个简单的过程介绍使用 ASP.Net Core 6.0 Web API 上传和下载多个文件。
步骤
首先在 Visual Studio 中创建一个空的 Web API 项目,目标框架选择.Net 6.0。
此项目中没有使用外部包。
创建一个 Services 文件夹,并在其中创建一个 FileService 类和 IFileService 接口。
我们在这个 FileService.cs 中使用了三个方法
UploadFile
DownloadFile
SizeConverter
由于我们需要一个文件夹来存储这些上传文件,因此我们在这里添加了一个参数来将文件夹名称作为字符串传递,它将存储所有上传的这些文件。
FileService.cs
using System.IO.Compression;namespace FileUploadAndDownload.Services;public class FileService : IFileService
{#region Propertyprivate readonly IWebHostEnvironment _webHostEnvironment;#endregion#region Constructorpublic FileService(IWebHostEnvironment webHostEnvironment){_webHostEnvironment = webHostEnvironment;}#endregion#region Upload Filepublic 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 Filepublic (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 Converterpublic 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
}SizeConverter 函数用于获取我们上传文件到服务器的实际大小。
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);
}让我们在 Program.cs 文件中添加这个服务依赖项
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();// 主要是添加下面这句代码,注入文件服务
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();创建一个 FileController,并 FileController 中的构造函数注入 IFileService。
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);}}
}我们可以在 swagger 和 postman 中测试我们的 API。

在这里,我们看到了我们创建的用于上传和下载的两个 API,因此让我们分别测试它们中的每一个。

在 subDirectory字段中 输入文件保存的文件夹名称,并在下面添加文件用于保存在服务器对应的子文件夹名称下。作为响应,我们会看到文件的总数和所有上传文件的总实际大小。

现在将检查下载 API。由于我们的文件夹中有多个文件,它将作为Zip 文件下载,我们需要将其解压缩以检查文件。

总结
使用Web API接口的方式上传和下载文件,适用于Blazor Server、Blazor Client、MAUI、Winform、WPF等客户端程序,后面有空写写客户端怎么调用这些接口。
本文源码:FileUploadAndDownload[1]
.... 保持学习 !!!
参考资料
[1]
FileUploadAndDownload: https://github.com/dotnet9/ASP.NET-Core-Test/tree/master/src/FileUploadAndDownload