这篇文章里,我们介绍在.net core webapi项目中操作MinIO。
首先要创建一个桶,命名为demo

英文文档看不太顺畅,在网上找了一个api中文文档,可供参考
.NET Client API参考文档 - MinIO 帮助文档 - 开发文档 - 文江博客
点击Buckets→Create Bucket创建桶

桶名可以命名为demo,点击确认

创建用户

创建AccessKey和SecretKey,点击Identity→Users→点击上一步创建的用户



把上面的AccessKey和SecretKey的值保存下来,可以在配置文件中使用。
创建个webapi项目,并添加Minio的NuGet包,这里我选3.1.13版本

将Minio注入进来,并将minio连接信息配置在appsetting,json文件中Startup.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
"AccessKey"和"SecretKey"可以用账号密码,也可以用配置中,新加用户中的配置信息
- {
- "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": ""
- }
- }
完整上传、下载代码
- 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 上传文件
- ///
- /// 上传文件
- ///
- /// 文件保存路径
- /// 文件
- ///
- [HttpPost]
- [AllowAnonymous]
- public async Task<dynamic> UploadFile(string filePath, List
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 下载文件
- ///
- /// 下载文件
- ///
- /// 文件地址
- ///
- [HttpGet]
- [AllowAnonymous]
- public async Task
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 获取指定文件目录
- ///
- /// 获取指定文件目录
- ///
- /// 文件路径(格式:["工程图纸/001","工程图纸/002"])
- /// 文件名,模糊查询
- ///
- [HttpPost]
- public async Task<object> GetFileListAsycn(string[] prefixArr, string fileName)
- {
- try
- {
- bool found = await _client.BucketExistsAsync(_bucketName);
- if (found)
- {
- List
- filePathList = new List
- ();
- 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 获取最上层目录
- ///
- /// 获取最上层目录
- ///
- ///
- [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()改成同步,即
- var files = _client.ListObjectsAsync(_bucketName, prefix, true);
- var filePaths = files.ToList().Wait();
这样,才能获取全部路径
获取根目录,非递归

其他api接口方法,查看官方文档,文档地址
Windows 的 MinIO 对象存储 — MinIO Object Storage for Windows