原文著者:Jay Krishna Reddy
原文リンク:https://www.c-sharpcorner.com/article/upload-and-download-multiple-files-using-web-api/
翻訳:砂漠の果ての狼(Google翻訳による補助。記事内のバージョンは.NET 6にアップグレード)
--- 本文開始 ---
本日は、ASP.NET Core 6.0 Web API を使用した複数ファイルのアップロードとダウンロードの簡単なプロセスを紹介します。
手順
まずVisual Studioで空のWeb APIプロジェクトを作成し、ターゲットフレームワークとして .NET 6.0 を選択します。
このプロジェクトでは外部パッケージは使用しません。
Services フォルダを作成し、その中に FileService クラスと IFileService インターフェースを作成します。
この FileService.cs では次の3つのメソッドを使用しています。
UploadFileDownloadFileSizeConverter
アップロードファイルを保存するフォルダが必要なため、フォルダ名を文字列で渡すパラメータを追加し、アップロードされたすべてのファイルをそのフォルダに保存します。
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
}
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 を作成し、そのコンストラクターで 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);
}
}
}
APIは swagger と postman でテストできます。

ここではアップロードとダウンロード用に作成した2つのAPIが表示されていますので、それぞれを個別にテストしてみましょう。

subDirectory フィールドにファイル保存先のフォルダ名を入力し、下にファイルを追加して、対応するサブフォルダ名でサーバーに保存します。応答として、ファイルの総数とアップロードされたすべてのファイルの合計実サイズが表示されます。

次にダウンロードAPIを確認します。フォルダ内に複数のファイルがあるため、Zip ファイルとしてダウンロードされ、解凍してファイルを確認する必要があります。

まとめ
Web API インターフェースを使用したファイルのアップロードとダウンロードは、Blazor Server、Blazor Client、MAUI、Winform、WPF などのクライアントプログラムに適用できます。後日、これらのインターフェースを呼び出すクライアント側の実装を紹介する予定です。
- 本記事のソースコード:FileUploadAndDownload
.... 学習を続けてください !!!