Upload and download multiple files using the Web API

Upload and download multiple files using the Web API

This is a simple process to introduce uploading and downloading multiple files using the ASP.NET Core 6.0 Web API.

最后更新 7/23/2022 9:37 AM
Jay Krishna Reddy
预计阅读 5 分钟
分类
ASP.NET Core
标签
.NET C# ASP.NET Core Web API

Author: Jay Krishna Reddy

Original link: www.c-sharpcorner.com/article/upload-and-download-multiple-files-using-web-api/

Translation: Wolf at the end of the desert (Google Translate added, the version in this article is upgraded using. NET 6)

--Start of the text--

Today, we will introduce uploading and downloading multiple files using the ASP.NET Core 6.0 Web API in a simple process.

step

首先在 Visual Studio 中创建一个空的 Web API 项目,目标框架选择.NET 6.0

No external packages are used in this project.

创建一个 Services 文件夹,并在其中创建一个 FileService 类和 IFileService 接口。

我们在这个 FileService.cs 中使用了三个方法

  • UploadFile
  • DownloadFile
  • SizeConverter

Since we need a folder to store these uploaded files, we added a parameter here to pass the folder name as a string, which will store all of these uploaded files.

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,并 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);
        }
    }
}

我们可以在 swaggerpostman 中测试我们的 API。

Here we see the two APIs we created for uploading and downloading, so let's test each of them separately.

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

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

summary

Upload and download files using the Web API interface, which is suitable for client programs such as Blazor Server, Blazor Client, MAUI, Winform, and WPF. Later, I will write how the client calls these interfaces when I have time.

... Keep learning!!!

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 6/22/2022

Localization of ASP.NET Core WebAPI (single resource file)

Microsoft's default method is that one class corresponds to multiple resource files, which is quite troublesome to use. This article introduces the use of single resource files, that is, all classes of the entire project correspond to a set of multi-language resource files.

继续阅读
同分类 / 同标签 4/13/2022

ASP.NET Core WebApi returns results Unified packaging practices

When WebApi unifies the return of results, I also thought further. First, how to better limit the return of unified formats, and secondly, the packaging of results must be simpler and more powerful. Through constant thinking and improvement, I finally had preliminary results, so I shared them. There was no end to learning and there was no end to thinking. I hope that I can share encouragement with you in this way.

继续阅读