MinIO (二) .net core中实现上传下载

这篇文章里,我们介绍在.net core webapi项目中操作MinIO。

首先要创建一个桶,命名为demo

英文文档看不太顺畅,在网上找了一个api中文文档,可供参考

.NET Client API参考文档 - MinIO 帮助文档 - 开发文档 - 文江博客

创建个webapi项目,并添加Minio的NuGet包,这里我选3.1.13版本

将Minio注入进来,并将minio连接信息配置在appsetting,json文件中Startup.cs

cs 复制代码
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient();

    #region minio客户端注入
    var minioClient = new MinioClient(Configuration["MinIO:Endpoint"]
        , Configuration["MinIO:AccessKey"]
        , Configuration["MinIO:SecretKey"]);
    services.AddSingleton(minioClient);
    #endregion

    #region 带权限的swagger
    services.AddSwaggerGen(options =>
    {
        //定义api文档
        options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "My API", Version = "v1" });
        //包含vs生成的注释文档
        //var xmlPath = Path.Combine(webHostEnvironment.ContentRootPath, Assembly.GetExecutingAssembly().GetName().Name + ".xml");
        //if (File.Exists(xmlPath))
        //{
        //    options.IncludeXmlComments(xmlPath, true);
        //}
        //描述安全信息
        options.AddSecurityDefinition(CookieAuthenticationDefaults.AuthenticationScheme, new OpenApiSecurityScheme()
        {
            Name = CookieAuthenticationDefaults.AuthenticationScheme,
            Scheme = CookieAuthenticationDefaults.AuthenticationScheme
        });
    });
    #endregion

    services.AddControllers();

    #region 不带权限的swagger
    //services.AddSwaggerGen(c =>
    //{
    //    c.SwaggerDoc("v1", new OpenApiInfo { Title = "MinioDemo.WebApi", Version = "v1" });
    //});
    #endregion


 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
    services.AddAuthorization();

}

appsetting,json

cs 复制代码
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  //minIO配置
  "MinIO": {
    //服务器IP
    "Endpoint": "localhost:9090",
    //账号
    "AccessKey": "minioadmin",
    //密码
    "SecretKey": "minioadmin",
    //默认存储桶
    "Bucket": "demo",
    //保存文件的根目录
    "BucketDirectory": "D:\\aaa\\bbb\\ccc"
  },
  "Kestrel": {
    "EndPoints": {
      "Http": {
        "Url": "http://*:5000"
      }
    }
  },
  "PDM": {
    "Secret": "",
    "Uri": ""
  }
}

完整上传、下载代码

cs 复制代码
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System;
using Minio;
using System.Linq;
using Minio.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Minio.DataModel;
using System.Reactive.Linq;
using System.Data;
using System.Reactive.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using Newtonsoft.Json;

namespace MinIOTest.Controllers
{
    [ApiController]
    [Route("api/[controller]/[action]")]
    //[Authorize]
    public class MinIOController : ControllerBase
    {
        string _bucketName = string.Empty;//默认桶
        private readonly MinioClient _client;
        private readonly IConfiguration _configuration;

        public MinIOController(
            MinioClient client,
            IConfiguration configuration
            )
        {
            _client = client;
            _configuration = configuration;
            _bucketName = configuration["MinIO:Bucket"];
        }

        #region 测试
        [HttpGet]
        public async Task<dynamic> test()
        {
            return new { bb = "bbb", cc = "ccc" };
        }
        #endregion

        #region 上传文件
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="filePath">文件保存路径</param>
        /// <param name="files">文件</param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        public async Task<dynamic> UploadFile(string filePath, List<IFormFile> files)
        {
            long size = files.Sum(f => f.Length);
            try
            {
                bool isExists = await _client.BucketExistsAsync(_bucketName);//桶是否存在
                //如果桶不存在则创建桶
                if (!isExists)
                {
                    await _client.MakeBucketAsync(_bucketName);
                }
                foreach (var formFile in files)
                {
                    string saveFileName = $"{Path.GetFileName(formFile.FileName)}";//存储        的文件名
                    string objectName = $"/{filePath}/{saveFileName}";//文件保存路径
                    if (formFile.Length > 0)
                    {
                        Stream stream = formFile.OpenReadStream();
                        await _client.PutObjectAsync(_bucketName,
                            objectName,
                            stream,
                            formFile.Length,
                            formFile.ContentType);
                    }
                }
            }
            catch (MinioException ex)
            {
                _logger.LogError($"文件上传错误:{ex}");
                return Ok(new { Success = false, Message = $"文件上传错误:{ex.Message}"                                         });
            }
            return Ok(new { Success = true, Count = files.Count, Size = size });
        }
        #endregion 上传文件

        #region 下载文件
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="fileName">文件地址</param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> DownloadFile(string fileName)
        {
            var memoryStream = new MemoryStream();

            try
            {
                await _client.StatObjectAsync(_bucketName, fileName);
                await _client.GetObjectAsync(_bucketName, fileName,
                                    (stream) =>
                                    {
                                        stream.CopyTo(memoryStream);
                                    });
                memoryStream.Position = 0;
            }
            catch (MinioException ex)
            {
                _logger.LogError($"下载附件发生错误:{ex}");
                return Ok(new { Success = false, Message = $"下载附件发生错误:{ex.Message}" });
            }

            return File(memoryStream, GetContentType(fileName));
        }
        #endregion 下载文件

        #region 获取文件ContentType类型
        private static string GetContentType(string fileName)
        {
            if (fileName.Contains(".jpg"))
            {
                return "image/jpg";
            }
            else if (fileName.Contains(".jpeg"))
            {
                return "image/jpeg";
            }
            else if (fileName.Contains(".png"))
            {
                return "image/png";
            }
            else if (fileName.Contains(".gif"))
            {
                return "image/gif";
            }
            else if (fileName.Contains(".pdf"))
            {
                return "application/pdf";
            }
            else if (fileName.Contains(".docx"))
            {
                return "application/msword";
            }
            else if (fileName.Contains(".txt"))
            {
                return "text/plain";
            }
            else
            {
                return "application/octet-stream";
            }
        }
        #endregion 获取文件类型

        #region 获取指定文件目录
        /// <summary>
        /// 获取指定文件目录
        /// </summary>
        /// <param name="prefixArr">文件路径(格式:["工程图纸/001","工程图纸/002"])        </param>
        /// <param name="fileName">文件名,模糊查询</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<object> GetFileListAsycn(string[] prefixArr, string fileName)
        {
            try
            {
                bool found = await _client.BucketExistsAsync(_bucketName);
                if (found)
                {
                    List<Item> filePathList = new List<Item>();
                    foreach (string prefix in prefixArr)
                    {
                        var files = _client.ListObjectsAsync(_bucketName, prefix, true);
                        var filePaths = files.ToList().Wait();
                        filePathList.InsertRange(filePathList.Count(), filePaths);
                    }
                    if (!string.IsNullOrEmpty(fileName))
                    {
                        filePathList = filePathList.Where(d =>         d.Key.Split('/').Last().Contains(fileName)).ToList();
                    }
                    return Ok(new { Success = true, Count = filePathList.Count(), Data = filePathList });
                }
                else
                {
                    return Ok(new { Success = false, Data = $"桶[{_bucketName}]不存在" });
                }
            }
            catch (MinioException ex)
            {
                _logger.LogError($"MinIO发生错误:{ex}");
                return Ok(new { Success = false, Data = $"MinIO发生错误:{ex.Message}" });
            }
        }
        #endregion 获取指定文件目录

        #region 获取最上层目录
        /// <summary>
        /// 获取最上层目录
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<object> GetDirectoryAsycn()
        {
            try
            {
                bool found = await _client.BucketExistsAsync(_bucketName);
                if (found)
                {
                    var files = _client.ListObjectsAsync(_bucketName, "", false);
                    var fileDirectory = files.ToList().Wait();
                    foreach (var file in fileDirectory)
                    {
                        file.Key = file.Key.Replace("/", "");
                    }
                    return Ok(new { Success = true, Data = fileDirectory });
                }
                else
                {
                    return Ok(new { Success = false, Data = $"桶[{_bucketName}]不存在" });
                }
            }
            catch (MinioException ex)
            {
                _logger.LogError($"MinIO发生错误:{ex}");
                return Ok(new { Success = false, Data = $"MinIO发生错误:{ex}" });
            }
        }
        #endregion 获取最上层目录  

    }
}

运行程序,如下图,上传接口

下载接口,输入文件地址

获取某个文件夹下的所有文件目录,递归获取

获取文件列表接口这里要要注意下,因为ListObjectsAsync这个接口是异步的,当自己写的接口执行完的时候,调用MinIO获取文件列表的接口还没执行完,所以,获取MinIO文件列表接口(ListObjectsAsync),要使用方法Wait()改成同步,即

cs 复制代码
var files = _client.ListObjectsAsync(_bucketName, prefix, true);
var filePaths = files.ToList().Wait();

这样,才能获取全部路径

获取根目录,非递归

其他api接口方法,查看官方文档,文档地址

Windows 的 MinIO 对象存储 --- MinIO Object Storage for Windows

.NET Client API参考文档 - MinIO 帮助文档 - 开发文档 - 文江博客

上一篇:MinIO (一)安装并生成windows服务

下一篇:

相关推荐
weixin_382395234 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__4 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.5 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~6 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华6 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子9 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅9 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni9 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学11 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端