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


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

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

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

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

    创建桶

    点击Buckets→Create Bucket创建桶

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

    创建用户和秘钥

    创建用户

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

    把上面的AccessKey和SecretKey的值保存下来,可以在配置文件中使用。

    创建WebApi项目

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

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

    1. public void ConfigureServices(IServiceCollection services)
    2. {
    3. services.AddHttpClient();
    4. #region minio客户端注入
    5. var minioClient = new MinioClient(Configuration["MinIO:Endpoint"]
    6. , Configuration["MinIO:AccessKey"]
    7. , Configuration["MinIO:SecretKey"]);
    8. services.AddSingleton(minioClient);
    9. #endregion
    10. #region 带权限的swagger
    11. services.AddSwaggerGen(options =>
    12. {
    13. //定义api文档
    14. options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "My API", Version = "v1" });
    15. //包含vs生成的注释文档
    16. //var xmlPath = Path.Combine(webHostEnvironment.ContentRootPath, Assembly.GetExecutingAssembly().GetName().Name + ".xml");
    17. //if (File.Exists(xmlPath))
    18. //{
    19. // options.IncludeXmlComments(xmlPath, true);
    20. //}
    21. //描述安全信息
    22. options.AddSecurityDefinition(CookieAuthenticationDefaults.AuthenticationScheme, new OpenApiSecurityScheme()
    23. {
    24. Name = CookieAuthenticationDefaults.AuthenticationScheme,
    25. Scheme = CookieAuthenticationDefaults.AuthenticationScheme
    26. });
    27. });
    28. #endregion
    29. services.AddControllers();
    30. #region 不带权限的swagger
    31. //services.AddSwaggerGen(c =>
    32. //{
    33. // c.SwaggerDoc("v1", new OpenApiInfo { Title = "MinioDemo.WebApi", Version = "v1" });
    34. //});
    35. #endregion
    36. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
    37. services.AddAuthorization();
    38. }

    appsetting,json

    "AccessKey"和"SecretKey"可以用账号密码,也可以用配置中,新加用户中的配置信息

    1. {
    2. "Logging": {
    3. "LogLevel": {
    4. "Default": "Information",
    5. "Microsoft": "Warning",
    6. "Microsoft.Hosting.Lifetime": "Information"
    7. }
    8. },
    9. "AllowedHosts": "*",
    10. //minIO配置
    11. "MinIO": {
    12. //服务器IP
    13. "Endpoint": "localhost:9090",
    14. //账号
    15. "AccessKey": "minioadmin",
    16. //密码
    17. "SecretKey": "minioadmin",
    18. //默认存储桶
    19. "Bucket": "demo",
    20. //保存文件的根目录
    21. "BucketDirectory": "D:\\aaa\\bbb\\ccc"
    22. },
    23. "Kestrel": {
    24. "EndPoints": {
    25. "Http": {
    26. "Url": "http://*:5000"
    27. }
    28. }
    29. },
    30. "PDM": {
    31. "Secret": "",
    32. "Uri": ""
    33. }
    34. }

    完整上传、下载代码

    1. using Microsoft.AspNetCore.Http;
    2. using Microsoft.AspNetCore.Mvc;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Threading.Tasks;
    6. using System;
    7. using Minio;
    8. using System.Linq;
    9. using Minio.Exceptions;
    10. using Microsoft.AspNetCore.Authorization;
    11. using Minio.DataModel;
    12. using System.Reactive.Linq;
    13. using System.Data;
    14. using System.Reactive.Threading.Tasks;
    15. using Microsoft.Extensions.Configuration;
    16. using Microsoft.Extensions.Logging;
    17. using System.Net.Http;
    18. using System.Text;
    19. using System.Text.Json;
    20. using Newtonsoft.Json;
    21. namespace MinIOTest.Controllers
    22. {
    23. [ApiController]
    24. [Route("api/[controller]/[action]")]
    25. //[Authorize]
    26. public class MinIOController : ControllerBase
    27. {
    28. string _bucketName = string.Empty;//默认桶
    29. private readonly MinioClient _client;
    30. private readonly IConfiguration _configuration;
    31. public MinIOController(
    32. MinioClient client,
    33. IConfiguration configuration
    34. )
    35. {
    36. _client = client;
    37. _configuration = configuration;
    38. _bucketName = configuration["MinIO:Bucket"];
    39. }
    40. #region 测试
    41. [HttpGet]
    42. public async Task<dynamic> test()
    43. {
    44. return new { bb = "bbb", cc = "ccc" };
    45. }
    46. #endregion
    47. #region 上传文件
    48. ///
    49. /// 上传文件
    50. ///
    51. /// 文件保存路径
    52. /// 文件
    53. ///
    54. [HttpPost]
    55. [AllowAnonymous]
    56. public async Task<dynamic> UploadFile(string filePath, List files)
    57. {
    58. long size = files.Sum(f => f.Length);
    59. try
    60. {
    61. bool isExists = await _client.BucketExistsAsync(_bucketName);//桶是否存在
    62. //如果桶不存在则创建桶
    63. if (!isExists)
    64. {
    65. await _client.MakeBucketAsync(_bucketName);
    66. }
    67. foreach (var formFile in files)
    68. {
    69. string saveFileName = $"{Path.GetFileName(formFile.FileName)}";//存储 的文件名
    70. string objectName = $"/{filePath}/{saveFileName}";//文件保存路径
    71. if (formFile.Length > 0)
    72. {
    73. Stream stream = formFile.OpenReadStream();
    74. await _client.PutObjectAsync(_bucketName,
    75. objectName,
    76. stream,
    77. formFile.Length,
    78. formFile.ContentType);
    79. }
    80. }
    81. }
    82. catch (MinioException ex)
    83. {
    84. _logger.LogError($"文件上传错误:{ex}");
    85. return Ok(new { Success = false, Message = $"文件上传错误:{ex.Message}" });
    86. }
    87. return Ok(new { Success = true, Count = files.Count, Size = size });
    88. }
    89. #endregion 上传文件
    90. #region 下载文件
    91. ///
    92. /// 下载文件
    93. ///
    94. /// 文件地址
    95. ///
    96. [HttpGet]
    97. [AllowAnonymous]
    98. public async Task DownloadFile(string fileName)
    99. {
    100. var memoryStream = new MemoryStream();
    101. try
    102. {
    103. await _client.StatObjectAsync(_bucketName, fileName);
    104. await _client.GetObjectAsync(_bucketName, fileName,
    105. (stream) =>
    106. {
    107. stream.CopyTo(memoryStream);
    108. });
    109. memoryStream.Position = 0;
    110. }
    111. catch (MinioException ex)
    112. {
    113. _logger.LogError($"下载附件发生错误:{ex}");
    114. return Ok(new { Success = false, Message = $"下载附件发生错误:{ex.Message}" });
    115. }
    116. return File(memoryStream, GetContentType(fileName));
    117. }
    118. #endregion 下载文件
    119. #region 获取文件ContentType类型
    120. private static string GetContentType(string fileName)
    121. {
    122. if (fileName.Contains(".jpg"))
    123. {
    124. return "image/jpg";
    125. }
    126. else if (fileName.Contains(".jpeg"))
    127. {
    128. return "image/jpeg";
    129. }
    130. else if (fileName.Contains(".png"))
    131. {
    132. return "image/png";
    133. }
    134. else if (fileName.Contains(".gif"))
    135. {
    136. return "image/gif";
    137. }
    138. else if (fileName.Contains(".pdf"))
    139. {
    140. return "application/pdf";
    141. }
    142. else if (fileName.Contains(".docx"))
    143. {
    144. return "application/msword";
    145. }
    146. else if (fileName.Contains(".txt"))
    147. {
    148. return "text/plain";
    149. }
    150. else
    151. {
    152. return "application/octet-stream";
    153. }
    154. }
    155. #endregion 获取文件类型
    156. #region 获取指定文件目录
    157. ///
    158. /// 获取指定文件目录
    159. ///
    160. /// 文件路径(格式:["工程图纸/001","工程图纸/002"])
    161. /// 文件名,模糊查询
    162. ///
    163. [HttpPost]
    164. public async Task<object> GetFileListAsycn(string[] prefixArr, string fileName)
    165. {
    166. try
    167. {
    168. bool found = await _client.BucketExistsAsync(_bucketName);
    169. if (found)
    170. {
    171. List filePathList = new List();
    172. foreach (string prefix in prefixArr)
    173. {
    174. var files = _client.ListObjectsAsync(_bucketName, prefix, true);
    175. var filePaths = files.ToList().Wait();
    176. filePathList.InsertRange(filePathList.Count(), filePaths);
    177. }
    178. if (!string.IsNullOrEmpty(fileName))
    179. {
    180. filePathList = filePathList.Where(d => d.Key.Split('/').Last().Contains(fileName)).ToList();
    181. }
    182. return Ok(new { Success = true, Count = filePathList.Count(), Data = filePathList });
    183. }
    184. else
    185. {
    186. return Ok(new { Success = false, Data = $"桶[{_bucketName}]不存在" });
    187. }
    188. }
    189. catch (MinioException ex)
    190. {
    191. _logger.LogError($"MinIO发生错误:{ex}");
    192. return Ok(new { Success = false, Data = $"MinIO发生错误:{ex.Message}" });
    193. }
    194. }
    195. #endregion 获取指定文件目录
    196. #region 获取最上层目录
    197. ///
    198. /// 获取最上层目录
    199. ///
    200. ///
    201. [HttpGet]
    202. public async Task<object> GetDirectoryAsycn()
    203. {
    204. try
    205. {
    206. bool found = await _client.BucketExistsAsync(_bucketName);
    207. if (found)
    208. {
    209. var files = _client.ListObjectsAsync(_bucketName, "", false);
    210. var fileDirectory = files.ToList().Wait();
    211. foreach (var file in fileDirectory)
    212. {
    213. file.Key = file.Key.Replace("/", "");
    214. }
    215. return Ok(new { Success = true, Data = fileDirectory });
    216. }
    217. else
    218. {
    219. return Ok(new { Success = false, Data = $"桶[{_bucketName}]不存在" });
    220. }
    221. }
    222. catch (MinioException ex)
    223. {
    224. _logger.LogError($"MinIO发生错误:{ex}");
    225. return Ok(new { Success = false, Data = $"MinIO发生错误:{ex}" });
    226. }
    227. }
    228. #endregion 获取最上层目录
    229. }
    230. }

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

    下载接口,输入文件地址

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

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

    1. var files = _client.ListObjectsAsync(_bucketName, prefix, true);
    2. var filePaths = files.ToList().Wait();

    这样,才能获取全部路径

    获取根目录,非递归

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

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

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

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

    下一篇:MinIO (三) 使用Webhook实时同步文件

  • 相关阅读:
    洛谷P4324 扭动的回文串
    Java实现简易版的【图书管理系统】
    VScode 关闭鼠标悬停提示
    为什么要让员工入职流程实现自动化
    vue——基于element嵌套表格+多选
    GitLab Runner 服务出现问题排查步骤
    [C++][opengl]使用opengl绘制一个简单三角形
    金仓数据库KingbaseES服务器应用参考手册--9. sys_test_fsync
    不想改bug?程序员必须学会使用的报错函数assert!(断言函数详解)
    springboot,spring框架返回204 status code的时候,会吞掉返回值
  • 原文地址:https://blog.csdn.net/qq_22325259/article/details/133874942