創建 Web API 來提供跨客戶端和服務器的文件上傳和下載是常有的事。本文將介紹如何通過 ASP.NET CORE 來實現。
首先在 Visual Studio 中創建空的 Web API 項目,然后選擇目標框架 .Net Core 3.1。
創建名為 FileController 的控制器,提供操作文件的接口。
namespace FileAPI.Controllers
{
? ? //[ApiController]
? ? [Route("api/[controller]")]
? ? public class FileController : ControllerBase
? ? {
? ? ? ? private readonly FileService _fileService;
? ? ? ? public FileController(FileService fileService)
? ? ? ? {
? ? ? ? ? ? _fileService = fileService;
? ? ? ? }
? ? ? ? // download file(s) to client according path: rootDirectory/subDirectory with single zip file
? ? ? ? [HttpGet("Download/{subDirectory}")]
? ? ? ? public IActionResult DownloadFiles(string subDirectory)
? ? ? ? {
? ? ? ? ? ? try
? ? ? ? ? ? {
? ? ? ? ? ? ? ? var (fileType, archiveData, archiveName) = _fileService.FetechFiles(subDirectory);
? ? ? ? ? ? ? ? return File(archiveData, fileType, archiveName);
? ? ? ? ? ? }
? ? ? ? ? ? catch (Exception exception)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return BadRequest($"Error: {exception.Message}");
? ? ? ? ? ? }
? ? ? ? }
? ? ? ??
? ? ? ? // upload file(s) to server that palce under path: rootDirectory/subDirectory
? ? ? ? [HttpPost("upload")]
? ? ? ? public IActionResult UploadFile([FromForm(Name = "files")] List<IFormFile> files, string subDirectory)
? ? ? ? {
? ? ? ? ? ? try
? ? ? ? ? ? {
? ? ? ? ? ? ? ? _fileService.SaveFile(files, subDirectory);
? ? ? ? ? ? ? ? return Ok(new { files.Count, Size = FileService.SizeConverter(files.Sum(f => f.Length)) });
? ? ? ? ? ? }
? ? ? ? ? ? catch (Exception exception)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return BadRequest($"Error: {exception.Message}");
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
創建服務層來實現文件傳輸的細節。?
namespace FileAPI.Services
{
? ? public class FileService
? ? {
? ? ? ? public void SaveFile(List<IFormFile> files, string subDirectory)
? ? ? ? {
? ? ? ? ? ? subDirectory = subDirectory ?? string.Empty;
? ? ? ? ? ? var target = Path.Combine("D:\\webroot\\", subDirectory);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? Directory.CreateDirectory(target);
? ? ? ? ? ? files.ForEach(async file =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if (file.Length <= 0) return;
? ? ? ? ? ? ? ? var filePath = Path.Combine(target, file.FileName);
? ? ? ? ? ? ? ? using (var stream = new FileStream(filePath, FileMode.Create))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? await file.CopyToAsync(stream);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? ? ? public (string fileType, byte[] archiveData, string archiveName) FetechFiles(string subDirectory)
? ? ? ? {
? ? ? ? ? ? var zipName = $"archive-{DateTime.Now.ToString("yyyy_MM_dd-HH_mm_ss")}.zip";
? ? ? ? ? ? var files = Directory.GetFiles(Path.Combine("D:\\webroot\\", subDirectory)).ToList();
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? using (var memoryStream = new MemoryStream())
? ? ? ? ? ? {
? ? ? ? ? ? ? ? using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? files.ForEach(file =>
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? var theFile = archive.CreateEntry(file);
? ? ? ? ? ? ? ? ? ? ? ? using (var streamWriter = new StreamWriter(theFile.Open()))
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? streamWriter.Write(File.ReadAllText(file));
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return ("application/zip", memoryStream.ToArray(), zipName);
? ? ? ? ? ? }
? ? ? ? ? ??
? ? ? ? }
? ? ? ? public static 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);
? ? ? ? ? ? switch (fileSize)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? case var _ when fileSize < kilobyte:
? ? ? ? ? ? ? ? ? ? return $"Less then 1KB";
? ? ? ? ? ? ? ? case var _ when fileSize < megabyte:
? ? ? ? ? ? ? ? ? ? return $"{Math.Round(fileSize / kilobyte, 0, MidpointRounding.AwayFromZero):##,###.##}KB";
? ? ? ? ? ? ? ? case var _ when fileSize < gigabyte:
? ? ? ? ? ? ? ? ? ? return $"{Math.Round(fileSize / megabyte, 2, MidpointRounding.AwayFromZero):##,###.##}MB";
? ? ? ? ? ? ? ? case var _ when fileSize >= gigabyte:
? ? ? ? ? ? ? ? ? ? return $"{Math.Round(fileSize / gigabyte, 2, MidpointRounding.AwayFromZero):##,###.##}GB";
? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? return "n/a";
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
現在一切都準備就緒,讓我們啟動我們的 Web API 應用程序并通過在Postman中填寫一些請求來完成測試步驟。
測試下載接口,首先我們建立我們的根目錄:“D:\webroot\” 和子目錄:“report”,然后在里面放一些文件。
文件夾下的文件:D:\webroot\report\
在 Postman 下發起請求:?
測試下載接口
1) 命名請求名稱。
2) 使用GET方法填寫相應的 URL。
3 ) 觸發請求并檢查響應。
測試上傳接口,在Postman上發起請求:
1)命名請求名稱。
?
2)使用POST方法填寫相應的 URL 。?
?? ?在 <Body> 標簽上:選擇表單數據
?? ?1、KEY:文件(類型選擇文件),VALUE:選擇您想要的任何文件。 ??
?? ?2、KEY:子目錄,VALUE:目標文件夾。 ? ?您可以根據需要上傳單個文件或多個文件。 ? ?KEY 的屬性名稱映射到 WEB API 參數的名稱。
?? ?
3)發出請求并檢查響應。
如果您想將您的 Web API 從 .Net Core 2.2 移植到 3.1,您需要注意一些事情
如果您的客戶端的數據表單(網頁)沒有給出特定名稱,則以下示例在 Web API .Net Core 2.2 下運行。
例如:
<form method=”post” enctype=”multipart/form-data” action=”/api/upload”>
<input type=”file” name=”” multiple />
<br />
<input type=”submit” value=”submit” />
</form>
[HttpPost(“upload”)]public async Task<IActionResult> UploadFile([FromForm]List<IFormFile> files){…}
但是對于 Net Core 3.1,您將無法從請求中綁定模型 IFormFile(這意味著列表:files.Count 始終返回零):?
綁定失敗
正確的方法是:
[HttpPost("upload")]public IActionResult UploadFile([FromForm(Name = ""] List<IFormFile> files, string subDirectory){...}?
參考鏈接:File uploads in ASP.NET Core
如果您喜歡此文章,請收藏、點贊、評論,謝謝,祝您快樂每一天。?