这篇文章里,我们介绍在.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 帮助文档 - 开发文档 - 文江博客
下一篇: