diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln
index 8c1778367..373a884f8 100644
--- a/aspnet-core/LINGYUN.MicroService.All.sln
+++ b/aspnet-core/LINGYUN.MicroService.All.sln
@@ -758,9 +758,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenIddict.AspN
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.Notifications", "modules\identity\LINGYUN.Abp.Identity.Notifications\LINGYUN.Abp.Identity.Notifications.csproj", "{54BBA043-317B-4A4F-B583-513D08BC25A7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Work.Handlers", "framework\wechat\LINGYUN.Abp.WeChat.Work.Handlers\LINGYUN.Abp.WeChat.Work.Handlers.csproj", "{79FA2CBA-2904-4D80-A217-DCC0A38F93C4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.WeChat.Work.Handlers", "framework\wechat\LINGYUN.Abp.WeChat.Work.Handlers\LINGYUN.Abp.WeChat.Work.Handlers.csproj", "{79FA2CBA-2904-4D80-A217-DCC0A38F93C4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Official.Handlers", "framework\wechat\LINGYUN.Abp.WeChat.Official.Handlers\LINGYUN.Abp.WeChat.Official.Handlers.csproj", "{E469F047-6AD0-4D2B-9900-46358DA3BC30}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.WeChat.Official.Handlers", "framework\wechat\LINGYUN.Abp.WeChat.Official.Handlers\LINGYUN.Abp.WeChat.Official.Handlers.csproj", "{E469F047-6AD0-4D2B-9900-46358DA3BC30}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OssManagement.Minio", "modules\oss-management\LINGYUN.Abp.OssManagement.Minio\LINGYUN.Abp.OssManagement.Minio.csproj", "{EB9F1905-1798-4766-8347-A8D2A9DBFAED}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.OssManagement.Minio.Tests", "tests\LINGYUN.Abp.OssManagement.Minio.Tests\LINGYUN.Abp.OssManagement.Minio.Tests.csproj", "{CCE5C620-E17A-4EB1-A17A-9F90311B197D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.OssManagement.Domain.Tests", "tests\LINGYUN.Abp.OssManagement.Domain.Tests\LINGYUN.Abp.OssManagement.Domain.Tests.csproj", "{F2AD691B-71B9-4B86-95BC-E020DA6B1E4A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1952,6 +1958,18 @@ Global
{E469F047-6AD0-4D2B-9900-46358DA3BC30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E469F047-6AD0-4D2B-9900-46358DA3BC30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E469F047-6AD0-4D2B-9900-46358DA3BC30}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EB9F1905-1798-4766-8347-A8D2A9DBFAED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EB9F1905-1798-4766-8347-A8D2A9DBFAED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EB9F1905-1798-4766-8347-A8D2A9DBFAED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EB9F1905-1798-4766-8347-A8D2A9DBFAED}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CCE5C620-E17A-4EB1-A17A-9F90311B197D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CCE5C620-E17A-4EB1-A17A-9F90311B197D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CCE5C620-E17A-4EB1-A17A-9F90311B197D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CCE5C620-E17A-4EB1-A17A-9F90311B197D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F2AD691B-71B9-4B86-95BC-E020DA6B1E4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F2AD691B-71B9-4B86-95BC-E020DA6B1E4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F2AD691B-71B9-4B86-95BC-E020DA6B1E4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F2AD691B-71B9-4B86-95BC-E020DA6B1E4A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2320,6 +2338,9 @@ Global
{54BBA043-317B-4A4F-B583-513D08BC25A7} = {52B5D4F7-237B-4E0A-A167-68442164F70A}
{79FA2CBA-2904-4D80-A217-DCC0A38F93C4} = {DD9BE9E7-F6BF-4869-BCD2-82F5072BDA21}
{E469F047-6AD0-4D2B-9900-46358DA3BC30} = {DD9BE9E7-F6BF-4869-BCD2-82F5072BDA21}
+ {EB9F1905-1798-4766-8347-A8D2A9DBFAED} = {B05CB08F-C088-4D6D-97EE-A94A5D1AE4A6}
+ {CCE5C620-E17A-4EB1-A17A-9F90311B197D} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F}
+ {F2AD691B-71B9-4B86-95BC-E020DA6B1E4A} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718}
diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
index 09f561a76..d184946ab 100644
--- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln
+++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
@@ -587,15 +587,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Demo.HttpApi",
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "exporter", "exporter", "{4A2CF141-F32D-45A0-8665-B3705667A6D2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Exporter.Application.Contracts", "framework\exporter\LINGYUN.Abp.Exporter.Application.Contracts\LINGYUN.Abp.Exporter.Application.Contracts.csproj", "{A3924A79-1ADC-458D-8764-3958297BDEB0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Exporter.Application.Contracts", "framework\exporter\LINGYUN.Abp.Exporter.Application.Contracts\LINGYUN.Abp.Exporter.Application.Contracts.csproj", "{A3924A79-1ADC-458D-8764-3958297BDEB0}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Exporter.Application", "framework\exporter\LINGYUN.Abp.Exporter.Application\LINGYUN.Abp.Exporter.Application.csproj", "{38A933EB-82F1-42A6-ABF3-F55975B4078E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Exporter.Application", "framework\exporter\LINGYUN.Abp.Exporter.Application\LINGYUN.Abp.Exporter.Application.csproj", "{38A933EB-82F1-42A6-ABF3-F55975B4078E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Exporter.Core", "framework\exporter\LINGYUN.Abp.Exporter.Core\LINGYUN.Abp.Exporter.Core.csproj", "{03C9FFB2-E9A3-4CCC-A6B1-8B248BFBCB65}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Exporter.Core", "framework\exporter\LINGYUN.Abp.Exporter.Core\LINGYUN.Abp.Exporter.Core.csproj", "{03C9FFB2-E9A3-4CCC-A6B1-8B248BFBCB65}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Exporter.MiniExcel", "framework\exporter\LINGYUN.Abp.Exporter.MiniExcel\LINGYUN.Abp.Exporter.MiniExcel.csproj", "{CBC64BD6-297B-48F6-A3BA-0DBB4B0F5A69}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Exporter.MiniExcel", "framework\exporter\LINGYUN.Abp.Exporter.MiniExcel\LINGYUN.Abp.Exporter.MiniExcel.csproj", "{CBC64BD6-297B-48F6-A3BA-0DBB4B0F5A69}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Exporter.MagicodesIE.Excel", "framework\exporter\LINGYUN.Abp.Exporter.MagicodesIE.Excel\LINGYUN.Abp.Exporter.MagicodesIE.Excel.csproj", "{319428B9-CE7F-4027-92FA-6311C4CE95FB}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Exporter.MagicodesIE.Excel", "framework\exporter\LINGYUN.Abp.Exporter.MagicodesIE.Excel\LINGYUN.Abp.Exporter.MagicodesIE.Excel.csproj", "{319428B9-CE7F-4027-92FA-6311C4CE95FB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OssManagement.Minio", "modules\oss-management\LINGYUN.Abp.OssManagement.Minio\LINGYUN.Abp.OssManagement.Minio.csproj", "{9AE3E97E-8846-4315-9546-FF97E97FD49F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1575,6 +1577,10 @@ Global
{319428B9-CE7F-4027-92FA-6311C4CE95FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{319428B9-CE7F-4027-92FA-6311C4CE95FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{319428B9-CE7F-4027-92FA-6311C4CE95FB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9AE3E97E-8846-4315-9546-FF97E97FD49F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9AE3E97E-8846-4315-9546-FF97E97FD49F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9AE3E97E-8846-4315-9546-FF97E97FD49F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9AE3E97E-8846-4315-9546-FF97E97FD49F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1866,6 +1872,7 @@ Global
{03C9FFB2-E9A3-4CCC-A6B1-8B248BFBCB65} = {4A2CF141-F32D-45A0-8665-B3705667A6D2}
{CBC64BD6-297B-48F6-A3BA-0DBB4B0F5A69} = {4A2CF141-F32D-45A0-8665-B3705667A6D2}
{319428B9-CE7F-4027-92FA-6311C4CE95FB} = {4A2CF141-F32D-45A0-8665-B3705667A6D2}
+ {9AE3E97E-8846-4315-9546-FF97E97FD49F} = {3AD66E47-B667-40D1-AE61-F5EC186241F7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1}
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs
index 99687ff14..ae96376ca 100644
--- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs
@@ -130,10 +130,12 @@ public async virtual Task DeleteAsync(string name)
// 阿里云oss在控制台设置即可,无需改变
var ossClient = await CreateClientAsync();
- if (BucketExists(ossClient, name))
+ if (!BucketExists(ossClient, name))
{
- ossClient.DeleteBucket(name);
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
}
+
+ ossClient.DeleteBucket(name);
}
public async virtual Task ExpireAsync(ExprieOssObjectRequest request)
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementContainer.cs
index cf9c14891..afbcc9547 100644
--- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementContainer.cs
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementContainer.cs
@@ -2,7 +2,7 @@
namespace LINGYUN.Abp.OssManagement;
-[BlobContainerName("abp-oss-management")]
+[BlobContainerName("abp-blobs")]
public class AbpOssManagementContainer
{
}
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/IOssContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/IOssContainer.cs
index a3a2994bd..5f5169a1b 100644
--- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/IOssContainer.cs
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/IOssContainer.cs
@@ -36,6 +36,10 @@ public interface IOssContainer
///
///
///
+ ///
+ /// When the bucket does not exist, an exception is thrown with the error code is
+ ///
+ ///
Task DeleteAsync(string name);
///
/// 删除Oss对象
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/OssObjectAcknowledgeHandler.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/OssObjectAcknowledgeHandler.cs
index 4ecc1b761..964708cc4 100644
--- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/OssObjectAcknowledgeHandler.cs
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/OssObjectAcknowledgeHandler.cs
@@ -22,9 +22,9 @@ public async virtual Task HandleEventAsync(OssObjectAcknowledgeEto eventData)
var ossContainer = _containerFactory.Create();
var tempPath = HttpUtility.UrlDecode(GetTempPath(eventData.TempPath));
- var tempObkect = HttpUtility.UrlDecode(GetTempObject(eventData.TempPath));
+ var tempObject = HttpUtility.UrlDecode(GetTempObject(eventData.TempPath));
- var ossObject = await ossContainer.GetObjectAsync(Bucket, tempObkect, tempPath, createPathIsNotExists: true);
+ var ossObject = await ossContainer.GetObjectAsync(Bucket, tempObject, tempPath, createPathIsNotExists: true);
using (ossObject.Content)
{
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xml b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xsd b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xsd
new file mode 100644
index 000000000..3f3946e28
--- /dev/null
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN.Abp.OssManagement.Minio.csproj b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN.Abp.OssManagement.Minio.csproj
new file mode 100644
index 000000000..4b84a0544
--- /dev/null
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN.Abp.OssManagement.Minio.csproj
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+ net8.0
+ LINGYUN.Abp.OssManagement.Minio
+ LINGYUN.Abp.OssManagement.Minio
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioModule.cs
new file mode 100644
index 000000000..141764965
--- /dev/null
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioModule.cs
@@ -0,0 +1,23 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using Volo.Abp.BlobStoring.Minio;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.OssManagement.Minio;
+
+[DependsOn(
+ typeof(AbpBlobStoringMinioModule),
+ typeof(AbpOssManagementDomainModule))]
+public class AbpOssManagementMinioModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddTransient();
+
+ context.Services.AddTransient(provider =>
+ provider
+ .GetRequiredService()
+ .Create()
+ .As());
+ }
+}
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer.cs
new file mode 100644
index 000000000..90b76d769
--- /dev/null
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer.cs
@@ -0,0 +1,558 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Minio;
+using Minio.DataModel.Args;
+using Minio.DataModel.ILM;
+using Minio.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.BlobStoring;
+using Volo.Abp.BlobStoring.Minio;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.OssManagement.Minio;
+
+///
+/// Oss容器的Minio实现
+///
+public class MinioOssContainer : IOssContainer, IOssObjectExpireor
+{
+ protected IMinioBlobNameCalculator MinioBlobNameCalculator { get; }
+ protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
+ protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
+
+ protected IClock Clock { get; }
+ protected ICurrentTenant CurrentTenant { get; }
+ protected ILogger Logger { get; }
+
+ public MinioOssContainer(
+ IClock clock,
+ ICurrentTenant currentTenant,
+ ILogger logger,
+ IMinioBlobNameCalculator minioBlobNameCalculator,
+ IBlobNormalizeNamingService blobNormalizeNamingService,
+ IBlobContainerConfigurationProvider configurationProvider)
+ {
+ Clock = clock;
+ Logger = logger;
+ CurrentTenant = currentTenant;
+ MinioBlobNameCalculator = minioBlobNameCalculator;
+ BlobNormalizeNamingService = blobNormalizeNamingService;
+ ConfigurationProvider = configurationProvider;
+ }
+
+ public async virtual Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(request.Bucket);
+
+ var prefixPath = GetPrefixPath();
+ var path = GetBlobPath(prefixPath, request.Path);
+
+ var args = new RemoveObjectsArgs()
+ .WithBucket(bucket)
+ .WithObjects(request.Objects.Select((x) => path + x.RemovePreFix("/")).ToList());
+
+ var response = await client.RemoveObjectsAsync(args);
+
+ var tcs = new TaskCompletionSource();
+
+ using var _ = response.Subscribe(
+ onNext: (error) =>
+ {
+ Logger.LogWarning("Batch deletion of objects failed, error details {code}: {message}", error.Code, error.Message);
+ },
+ onError: tcs.SetException,
+ onCompleted: () => tcs.SetResult(true));
+
+ await tcs.Task;
+ }
+
+ public async virtual Task CreateAsync(string name)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(name);
+
+ if (await BucketExists(client, bucket))
+ {
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists);
+ }
+
+ await client.MakeBucketAsync(new MakeBucketArgs().WithBucket(bucket));
+
+ return new OssContainer(
+ name,
+ Clock.Now,
+ 0L,
+ Clock.Now,
+ new Dictionary());
+ }
+
+ public async virtual Task CreateObjectAsync(CreateOssObjectRequest request)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(request.Bucket);
+ var prefixPath = GetPrefixPath();
+ var objectPath = GetBlobPath(prefixPath, request.Path);
+ var objectName = objectPath.IsNullOrWhiteSpace()
+ ? request.Object
+ : objectPath + request.Object;
+
+ if (!request.Overwrite && await ObjectExists(client, bucket, objectName))
+ {
+ throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists);
+ }
+
+ // 没有bucket则创建
+ if (!await BucketExists(client, bucket))
+ {
+ var configuration = GetMinioConfiguration();
+ if (!configuration.CreateBucketIfNotExists)
+ {
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
+ }
+ await client.MakeBucketAsync(new MakeBucketArgs().WithBucket(bucket));
+ }
+ if (request.Content.IsNullOrEmpty())
+ {
+ var emptyContent = "This is an OSS object that simulates a directory.".GetBytes();
+ request.SetContent(new MemoryStream(emptyContent));
+ }
+ var putResponse = await client.PutObjectAsync(new PutObjectArgs()
+ .WithBucket(bucket)
+ .WithObject(objectName)
+ .WithStreamData(request.Content)
+ .WithObjectSize(request.Content.Length));
+
+ if (request.ExpirationTime.HasValue)
+ {
+ var lifecycleRule = new LifecycleRule
+ {
+ Status = "Enabled",
+ ID = putResponse.Etag,
+ Expiration = new Expiration(Clock.Now.Add(request.ExpirationTime.Value))
+ };
+ var lifecycleConfiguration = new LifecycleConfiguration();
+ lifecycleConfiguration.Rules.Add(lifecycleRule);
+
+ var lifecycleArgs = new SetBucketLifecycleArgs()
+ .WithBucket(bucket)
+ .WithLifecycleConfiguration(lifecycleConfiguration);
+
+ await client.SetBucketLifecycleAsync(lifecycleArgs);
+ }
+
+ var ossObject = new OssObject(
+ !objectPath.IsNullOrWhiteSpace()
+ ? objectName.Replace(objectPath, "")
+ : objectName,
+ objectPath.Replace(prefixPath, ""),
+ putResponse.Etag,
+ Clock.Now,
+ putResponse.Size,
+ Clock.Now,
+ new Dictionary(),
+ objectName.EndsWith('/'))
+ {
+ FullName = objectName.Replace(prefixPath, "")
+ };
+
+ if (!Equals(request.Content, Stream.Null))
+ {
+ request.Content.Seek(0, SeekOrigin.Begin);
+ ossObject.SetContent(request.Content);
+ }
+
+ return ossObject;
+ }
+
+ public async virtual Task DeleteAsync(string name)
+ {
+ var client = GetMinioClient();
+ var bucket = GetBucket(name);
+
+ if (!await BucketExists(client, bucket))
+ {
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
+ }
+
+ // 非空目录无法删除
+ var tcs = new TaskCompletionSource();
+ var listObjectObs = client.ListObjectsAsync(
+ new ListObjectsArgs()
+ .WithBucket(bucket));
+
+ var listObjects = new List();
+ using var _ = listObjectObs.Subscribe(
+ (item) =>
+ {
+ listObjects.Add(item.Key);
+ tcs.TrySetResult(true);
+ },
+ (ex) => tcs.TrySetException(ex),
+ () => tcs.TrySetResult(true));
+
+ await tcs.Task;
+
+ if (listObjects.Count > 0)
+ {
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerDeleteWithNotEmpty);
+ }
+
+ var deleteBucketArgs = new RemoveBucketArgs()
+ .WithBucket(bucket);
+
+ await client.RemoveBucketAsync(deleteBucketArgs);
+ }
+
+ public async virtual Task DeleteObjectAsync(GetOssObjectRequest request)
+ {
+ if (request.Object.EndsWith('/'))
+ {
+ // Minio系统设计并不支持目录的形式
+ // 如果是目录的形式,那必定有文件存在,抛出目录不为空即可
+ throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty);
+ }
+
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(request.Bucket);
+
+ var prefixPath = GetPrefixPath();
+ var objectPath = GetBlobPath(prefixPath, request.Path);
+ var objectName = objectPath.IsNullOrWhiteSpace()
+ ? request.Object
+ : objectPath + request.Object;
+
+ if (await BucketExists(client, bucket) &&
+ await ObjectExists(client, bucket, objectName))
+ {
+ var removeObjectArgs = new RemoveObjectArgs()
+ .WithBucket(bucket)
+ .WithObject(objectName);
+
+ await client.RemoveObjectAsync(removeObjectArgs);
+ }
+ }
+
+ public async virtual Task ExistsAsync(string name)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(name);
+
+ return await BucketExists(client, bucket);
+ }
+
+ public async virtual Task ExpireAsync(ExprieOssObjectRequest request)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(request.Bucket);
+
+ var bucketListResult = await client.ListBucketsAsync();
+ var expiredBuckets = bucketListResult.Buckets.Take(request.Batch);
+
+ foreach (var expiredBucket in expiredBuckets)
+ {
+ var listObjectArgs = new ListObjectsArgs()
+ .WithBucket(expiredBucket.Name);
+
+ var expiredObjectItem = client.ListObjectsAsync(listObjectArgs);
+
+ var tcs = new TaskCompletionSource();
+ using var _ = expiredObjectItem.Subscribe(
+ onNext: (item) =>
+ {
+ var lifecycleRule = new LifecycleRule
+ {
+ Status = "Enabled",
+ ID = item.Key,
+ Expiration = new Expiration(Clock.Normalize(request.ExpirationTime.DateTime))
+ };
+ var lifecycleConfiguration = new LifecycleConfiguration();
+ lifecycleConfiguration.Rules.Add(lifecycleRule);
+
+ var lifecycleArgs = new SetBucketLifecycleArgs()
+ .WithBucket(bucket)
+ .WithLifecycleConfiguration(lifecycleConfiguration);
+
+ var _ = client.SetBucketLifecycleAsync(lifecycleArgs);
+ },
+ onError: tcs.SetException,
+ onCompleted: () => tcs.SetResult(true)
+ );
+
+ await tcs.Task;
+ }
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(name);
+
+ var bucketListResult = await client.ListBucketsAsync();
+
+ var bucketInfo = bucketListResult.Buckets.FirstOrDefault((x) => x.Name == bucket);
+ if (bucketInfo == null)
+ {
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
+ }
+
+ return new OssContainer(
+ bucketInfo.Name,
+ bucketInfo.CreationDateDateTime,
+ 0L,
+ bucketInfo.CreationDateDateTime,
+ new Dictionary());
+ }
+
+ public async virtual Task GetListAsync(GetOssContainersRequest request)
+ {
+ var client = GetMinioClient();
+
+ var bucketListResult = await client.ListBucketsAsync();
+
+ var totalCount = bucketListResult.Buckets.Count;
+
+ var resultObjects = bucketListResult.Buckets
+ .AsQueryable()
+ .OrderBy(x => x.Name)
+ .PageBy(request.Current, request.MaxKeys ?? 10)
+ .Select(x => new OssContainer(
+ x.Name,
+ x.CreationDateDateTime,
+ 0L,
+ null,
+ new Dictionary()))
+ .ToList();
+
+ return new GetOssContainersResponse(
+ request.Prefix,
+ request.Marker,
+ null,
+ totalCount,
+ resultObjects);
+ }
+
+ public async virtual Task GetObjectAsync(GetOssObjectRequest request)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(request.Bucket);
+
+ var prefixPath = GetPrefixPath();
+ var objectPath = GetBlobPath(prefixPath, request.Path);
+ var objectName = objectPath.IsNullOrWhiteSpace()
+ ? request.Object
+ : objectPath.EnsureEndsWith('/') + request.Object;
+
+ if (!await ObjectExists(client, bucket, objectName))
+ {
+ throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound);
+ }
+
+ var memoryStream = new MemoryStream();
+ var getObjectArgs = new GetObjectArgs()
+ .WithBucket(bucket)
+ .WithObject(objectName)
+ .WithCallbackStream((stream) =>
+ {
+ if (stream != null)
+ {
+ stream.CopyTo(memoryStream);
+ memoryStream.Seek(0, SeekOrigin.Begin);
+ }
+ else
+ {
+ memoryStream = null;
+ }
+ });
+ var getObjectResult = await client.GetObjectAsync(getObjectArgs);
+
+ var ossObject = new OssObject(
+ !objectPath.IsNullOrWhiteSpace()
+ ? getObjectResult.ObjectName.Replace(objectPath, "")
+ : getObjectResult.ObjectName,
+ request.Path,
+ getObjectResult.ETag,
+ getObjectResult.LastModified,
+ memoryStream.Length,
+ getObjectResult.LastModified,
+ getObjectResult.MetaData,
+ getObjectResult.ObjectName.EndsWith("/"))
+ {
+ FullName = getObjectResult.ObjectName.Replace(prefixPath, "")
+ };
+
+ if (memoryStream.Length > 0)
+ {
+ ossObject.SetContent(memoryStream);
+ }
+
+ if (!request.Process.IsNullOrWhiteSpace())
+ {
+ // TODO: 文件流处理
+ }
+
+ return ossObject;
+ }
+
+ public async virtual Task GetObjectsAsync(GetOssObjectsRequest request)
+ {
+ var client = GetMinioClient();
+
+ var bucket = GetBucket(request.BucketName);
+
+ var prefixPath = GetPrefixPath();
+ var objectPath = GetBlobPath(prefixPath, request.Prefix);
+ var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace()
+ ? request.Marker.Replace(objectPath, "")
+ : request.Marker;
+
+ var listObjectArgs = new ListObjectsArgs()
+ .WithBucket(bucket)
+ .WithPrefix(objectPath);
+
+ var tcs = new TaskCompletionSource();
+
+ var listObjectResult = client.ListObjectsAsync(listObjectArgs);
+
+ var resultObjects = new List();
+
+ using var _ = listObjectResult.Subscribe(
+ onNext: (item) =>
+ {
+ resultObjects.Add(new OssObject(
+ !objectPath.IsNullOrWhiteSpace()
+ ? item.Key.Replace(objectPath, "")
+ : item.Key,
+ request.Prefix,
+ item.ETag,
+ item.LastModifiedDateTime,
+ item.Size.To(),
+ item.LastModifiedDateTime,
+ new Dictionary(),
+ item.IsDir));
+ },
+ onError: (ex) =>
+ {
+ tcs.TrySetException(ex);
+ },
+ onCompleted: () =>
+ {
+ tcs.SetResult(true);
+ }
+ );
+
+ await tcs.Task;
+
+ var totalCount = resultObjects.Count;
+ resultObjects = resultObjects
+ .AsQueryable()
+ .OrderBy(x => x.Name)
+ .PageBy(request.Current, request.MaxKeys ?? 10)
+ .ToList();
+
+ return new GetOssObjectsResponse(
+ bucket,
+ request.Prefix,
+ request.Marker,
+ marker,
+ "/",
+ totalCount,
+ resultObjects);
+ }
+
+ protected virtual IMinioClient GetMinioClient()
+ {
+ var configuration = GetMinioConfiguration();
+
+ var client = new MinioClient()
+ .WithEndpoint(configuration.EndPoint)
+ .WithCredentials(configuration.AccessKey, configuration.SecretKey);
+
+ if (configuration.WithSSL)
+ {
+ client.WithSSL();
+ }
+
+ return client.Build();
+ }
+
+ protected async virtual Task BucketExists(IMinioClient client, string bucket)
+ {
+ var args = new BucketExistsArgs().WithBucket(bucket);
+
+ return await client.BucketExistsAsync(args);
+ }
+
+ protected async virtual Task ObjectExists(IMinioClient client, string bucket, string @object)
+ {
+ if (await client.BucketExistsAsync(new BucketExistsArgs().WithBucket(bucket)))
+ {
+ try
+ {
+ await client.StatObjectAsync(new StatObjectArgs().WithBucket(bucket).WithObject(@object));
+ }
+ catch (Exception e)
+ {
+ if (e is ObjectNotFoundException)
+ {
+ return false;
+ }
+
+ throw;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ protected virtual MinioBlobProviderConfiguration GetMinioConfiguration()
+ {
+ var configuration = ConfigurationProvider.Get();
+
+ return configuration.GetMinioConfiguration();
+ }
+
+ protected virtual string GetBucket(string bucket)
+ {
+ var configuration = ConfigurationProvider.Get();
+ var minioConfiguration = configuration.GetMinioConfiguration();
+
+ return bucket.IsNullOrWhiteSpace()
+ ? BlobNormalizeNamingService.NormalizeContainerName(configuration, minioConfiguration.BucketName!)
+ : BlobNormalizeNamingService.NormalizeContainerName(configuration, bucket);
+ }
+
+ protected virtual string GetPrefixPath()
+ {
+ return CurrentTenant.Id == null
+ ? $"host/"
+ : $"tenants/{CurrentTenant.Id.Value.ToString("D")}/";
+ }
+
+ protected virtual string GetBlobPath(string basePath, string path)
+ {
+ var resultPath = $"{basePath}{(
+ path.IsNullOrWhiteSpace() ? "" :
+ path.Replace("./", "").RemovePreFix("/"))}";
+
+ return resultPath.Replace("//", "");
+ }
+}
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainerFactory.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainerFactory.cs
new file mode 100644
index 000000000..90ae1358f
--- /dev/null
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainerFactory.cs
@@ -0,0 +1,44 @@
+using Microsoft.Extensions.Logging;
+using Volo.Abp.BlobStoring;
+using Volo.Abp.BlobStoring.Minio;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.OssManagement.Minio;
+public class MinioOssContainerFactory : IOssContainerFactory
+{
+ protected IMinioBlobNameCalculator MinioBlobNameCalculator { get; }
+ protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
+ protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
+
+ protected IClock Clock { get; }
+ protected ICurrentTenant CurrentTenant { get; }
+ protected ILogger Logger { get; }
+
+ public MinioOssContainerFactory(
+ IClock clock,
+ ICurrentTenant currentTenant,
+ ILogger logger,
+ IMinioBlobNameCalculator minioBlobNameCalculator,
+ IBlobNormalizeNamingService blobNormalizeNamingService,
+ IBlobContainerConfigurationProvider configurationProvider)
+ {
+ Clock = clock;
+ Logger = logger;
+ CurrentTenant = currentTenant;
+ MinioBlobNameCalculator = minioBlobNameCalculator;
+ BlobNormalizeNamingService = blobNormalizeNamingService;
+ ConfigurationProvider = configurationProvider;
+ }
+
+ public IOssContainer Create()
+ {
+ return new MinioOssContainer(
+ Clock,
+ CurrentTenant,
+ Logger,
+ MinioBlobNameCalculator,
+ BlobNormalizeNamingService,
+ ConfigurationProvider);
+ }
+}
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/README.md b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/README.md
new file mode 100644
index 000000000..8155334ca
--- /dev/null
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/README.md
@@ -0,0 +1,19 @@
+# LINGYUN.Abp.OssManagement.Minio
+
+Oss容器管理接口的Minio实现
+
+## 配置使用
+
+模块按需引用
+
+相关配置项请参考 [BlobStoring Minio](https://abp.io/docs/latest/framework/infrastructure/blob-storing/minio)
+
+```csharp
+[DependsOn(typeof(AbpOssManagementMinioModule))]
+public class YouProjectModule : AbpModule
+{
+ // other
+}
+```
+
+
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Nexus/LINGYUN/Abp/OssManagement/Nexus/NexusOssContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Nexus/LINGYUN/Abp/OssManagement/Nexus/NexusOssContainer.cs
index 49b845e7c..07c80c134 100644
--- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Nexus/LINGYUN/Abp/OssManagement/Nexus/NexusOssContainer.cs
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Nexus/LINGYUN/Abp/OssManagement/Nexus/NexusOssContainer.cs
@@ -118,10 +118,12 @@ public async virtual Task DeleteAsync(string name)
var nexusComponentListResult = await NexusLookupService.ListComponentAsync(nexusSearchArgs);
var nexusComponent = nexusComponentListResult.Items.FirstOrDefault();
- if (nexusComponent != null)
+ if (nexusComponent == null)
{
- await NexusComponentManager.DeleteAsync(nexusComponent.Id);
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
}
+
+ await NexusComponentManager.DeleteAsync(nexusComponent.Id);
}
public async virtual Task DeleteObjectAsync(GetOssObjectRequest request)
diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Tencent/LINGYUN/Abp/OssManagement/Tencent/TencentOssContainer.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Tencent/LINGYUN/Abp/OssManagement/Tencent/TencentOssContainer.cs
index fdc0cf0a2..ee329d1d7 100644
--- a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Tencent/LINGYUN/Abp/OssManagement/Tencent/TencentOssContainer.cs
+++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Tencent/LINGYUN/Abp/OssManagement/Tencent/TencentOssContainer.cs
@@ -151,11 +151,12 @@ public async virtual Task DeleteAsync(string name)
// 阿里云oss在控制台设置即可,无需改变
var ossClient = await CreateClientAsync();
- if (BucketExists(ossClient, name))
+ if (!BucketExists(ossClient, name))
{
- var deleteBucketRequest = new DeleteBucketRequest(name);
- ossClient.DeleteBucket(deleteBucketRequest);
+ throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
}
+ var deleteBucketRequest = new DeleteBucketRequest(name);
+ ossClient.DeleteBucket(deleteBucketRequest);
}
public async virtual Task ExpireAsync(ExprieOssObjectRequest request)
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
index 9823acb71..98101e714 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
@@ -205,6 +205,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
index 1d86ea567..330796a07 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
@@ -386,7 +386,7 @@ private void ConfigureKestrelServer()
});
}
- private void ConfigureBlobStoring()
+ private void ConfigureBlobStoring(IConfiguration configuration)
{
Configure(options =>
{
@@ -396,6 +396,11 @@ private void ConfigureBlobStoring()
{
fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "blobs");
});
+
+ //containerConfiguration.UseMinio(minio =>
+ //{
+ // configuration.GetSection("Minio").Bind(minio);
+ //});
});
});
}
@@ -405,9 +410,9 @@ private void ConfigureBackgroundTasks()
Configure(options =>
{
options.NodeName = ApplicationName;
- options.JobCleanEnabled = false;
- options.JobFetchEnabled = false;
- options.JobCheckEnabled = false;
+ options.JobCleanEnabled = true;
+ options.JobFetchEnabled = true;
+ options.JobCheckEnabled = true;
});
}
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
index 2141cca65..ca7aaa23a 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
@@ -45,9 +45,6 @@
using LINGYUN.Abp.Identity.OrganizaztionUnits;
using LINGYUN.Abp.Identity.Session.AspNetCore;
using LINGYUN.Abp.Identity.WeChat;
-using LINGYUN.Abp.IdentityServer;
-using LINGYUN.Abp.IdentityServer.EntityFrameworkCore;
-using LINGYUN.Abp.IdentityServer.Session;
using LINGYUN.Abp.IdGenerator;
using LINGYUN.Abp.IM.SignalR;
using LINGYUN.Abp.Localization.CultureMap;
@@ -109,7 +106,6 @@
using LINGYUN.Platform.Settings.VueVbenAdmin;
using LINGYUN.Platform.Theme.VueVbenAdmin;
using LY.MicroService.Applications.Single.EntityFrameworkCore;
-using Microsoft.AspNetCore.Authorization;
using Volo.Abp;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
@@ -126,7 +122,6 @@
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.Identity;
-using Volo.Abp.PermissionManagement.IdentityServer;
using Volo.Abp.SettingManagement;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.Threading;
@@ -180,10 +175,11 @@ namespace LY.MicroService.Applications.Single;
typeof(AbpOpenIddictWeChatModule),
typeof(AbpOpenIddictWeChatWorkModule),
+ // typeof(AbpOssManagementMinioModule), // 取消注释以使用Minio
+ typeof(AbpOssManagementFileSystemImageSharpModule),
typeof(AbpOssManagementDomainModule),
typeof(AbpOssManagementApplicationModule),
typeof(AbpOssManagementHttpApiModule),
- typeof(AbpOssManagementFileSystemImageSharpModule),
typeof(AbpOssManagementSettingManagementModule),
typeof(PlatformDomainModule),
@@ -351,7 +347,6 @@ public override void ConfigureServices(ServiceConfigurationContext context)
ConfigureIdempotent();
ConfigureMvcUiTheme();
ConfigureDataSeeder();
- ConfigureBlobStoring();
ConfigureLocalization();
ConfigureKestrelServer();
ConfigureBackgroundTasks();
@@ -365,6 +360,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
ConfigureAuthServer(configuration);
ConfigureSwagger(context.Services);
ConfigureEndpoints(context.Services);
+ ConfigureBlobStoring(configuration);
ConfigureMultiTenancy(configuration);
ConfigureJsonSerializer(configuration);
ConfigureTextTemplating(configuration);
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.Development.json b/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.Development.json
index 8b8cd288b..883cb8c70 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.Development.json
@@ -223,6 +223,14 @@
"Elasticsearch": {
"NodeUris": "http://127.0.0.1:9200"
},
+ "Minio": {
+ "WithSSL": false,
+ "BucketName": "blobs",
+ "EndPoint": "127.0.0.1:19000",
+ "AccessKey": "ZD43kNpimiJf9mCuomTP",
+ "SecretKey": "w8IqMgi4Tnz0DGzN8jZ7IJWq7OEdbUnAU0jlZxQK",
+ "CreateBucketIfNotExists": false
+ },
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN.Abp.OssManagement.Domain.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN.Abp.OssManagement.Domain.Tests.csproj
new file mode 100644
index 000000000..2dfe2a391
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN.Abp.OssManagement.Domain.Tests.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net8.0
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestBase.cs
new file mode 100644
index 000000000..ebefcecb3
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestBase.cs
@@ -0,0 +1,6 @@
+using LINGYUN.Abp.Tests;
+
+namespace LINGYUN.Abp.OssManagement;
+public abstract class AbpOssManagementDomainTestBase : AbpTestsBase
+{
+}
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestsModule.cs b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestsModule.cs
new file mode 100644
index 000000000..10ae21037
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestsModule.cs
@@ -0,0 +1,11 @@
+using LINGYUN.Abp.Tests;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.OssManagement;
+
+[DependsOn(
+ typeof(AbpOssManagementDomainModule),
+ typeof(AbpTestsBaseModule))]
+public class AbpOssManagementDomainTestsModule : AbpModule
+{
+}
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/OssContainer_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/OssContainer_Tests.cs
new file mode 100644
index 000000000..74a2b5bd8
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/OssContainer_Tests.cs
@@ -0,0 +1,248 @@
+using Shouldly;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Modularity;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.Testing;
+using Xunit;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace LINGYUN.Abp.OssManagement;
+public abstract class OssContainer_Tests : AbpIntegratedTest
+ where TStartupModule : IAbpModule
+{
+ private readonly ICurrentTenant _currentTenant;
+ private readonly IOssContainerFactory _ossContainerFactory;
+
+ protected OssContainer_Tests()
+ {
+ _currentTenant = GetRequiredService();
+ _ossContainerFactory = GetRequiredService();
+ }
+
+ [Theory]
+ [InlineData("test-bucket")]
+ public async virtual Task Should_Creat_And_Get_Bucket(string bucket)
+ {
+ var container = _ossContainerFactory.Create();
+
+ var ossContainer = await container.CreateAsync(bucket);
+
+ ossContainer.ShouldNotBeNull();
+ ossContainer.Name.ShouldBe(bucket);
+
+ await container.DeleteAsync(bucket);
+ }
+
+ [Theory]
+ [InlineData("test-bucket")]
+ public async virtual Task Should_Get_Exists_Bucket(string bucket)
+ {
+ var container = _ossContainerFactory.Create();
+
+ await container.CreateAsync(bucket);
+
+ var getContainer = await container.GetAsync(bucket);
+
+ getContainer.ShouldNotBeNull();
+ getContainer.Name.ShouldBe(bucket);
+
+ await container.DeleteAsync(bucket);
+ }
+
+ [Theory]
+ [InlineData("test-bucket")]
+ public async virtual Task Should_Delete_Bucket(string bucket)
+ {
+ var container = _ossContainerFactory.Create();
+
+ await container.CreateAsync(bucket);
+
+ await container.DeleteAsync(bucket);
+
+ var getNotFoundException = await Assert.ThrowsAsync(async () =>
+ await container.GetAsync(bucket)
+ );
+
+ getNotFoundException.Code.ShouldBe(OssManagementErrorCodes.ContainerNotFound);
+
+ var deleteNotFoundException = await Assert.ThrowsAsync(async () =>
+ await container.DeleteAsync(bucket)
+ );
+
+ deleteNotFoundException.Code.ShouldBe(OssManagementErrorCodes.ContainerNotFound);
+ }
+
+ [Theory]
+ [InlineData("test-bucket", "test-object-1")]
+ [InlineData("test-bucket", "test-folder/test-object-1")]
+ public async virtual Task Should_Save_And_Get_Object(string bucket, string @object)
+ {
+ var container = _ossContainerFactory.Create();
+
+ if (!await container.ExistsAsync(bucket))
+ {
+ await container.CreateAsync(bucket);
+ }
+
+ var testContent = "test content".GetBytes();
+ using var stream = new MemoryStream(testContent);
+
+ var createObject = await container.CreateObjectAsync(
+ new CreateOssObjectRequest(
+ bucket,
+ @object,
+ stream));
+
+ var getOssObject = await container.GetObjectAsync(
+ new GetOssObjectRequest(
+ bucket,
+ @object));
+
+ var result = await getOssObject.Content.GetAllBytesAsync();
+ result.SequenceEqual(testContent).ShouldBeTrue();
+
+ await container.DeleteObjectAsync(
+ new GetOssObjectRequest(
+ bucket,
+ @object));
+
+ await container.DeleteAsync(bucket);
+ }
+
+ [Theory]
+ [InlineData("test-bucket", "test-object-1")]
+ [InlineData("test-bucket", "test-folder/test-object-1")]
+ public async virtual Task Should_Delete_Object(string bucket, string @object)
+ {
+ var container = _ossContainerFactory.Create();
+
+ if (!await container.ExistsAsync(bucket))
+ {
+ await container.CreateAsync(bucket);
+ }
+
+ var testContent = "test content".GetBytes();
+ using var stream = new MemoryStream(testContent);
+
+ await container.CreateObjectAsync(
+ new CreateOssObjectRequest(
+ bucket,
+ @object,
+ stream));
+
+ var getOssObjectRequest = new GetOssObjectRequest(
+ bucket,
+ @object);
+ await container.DeleteObjectAsync(getOssObjectRequest);
+
+ var getNotFoundException = await Assert.ThrowsAsync(async () =>
+ await container.GetObjectAsync(getOssObjectRequest)
+ );
+
+ getNotFoundException.Code.ShouldBe(OssManagementErrorCodes.ObjectNotFound);
+
+ await container.DeleteAsync(bucket);
+ }
+
+ [Theory]
+ [InlineData("test-bucket")]
+ public async virtual Task Should_Bulk_Delete_Object(string bucket)
+ {
+ var container = _ossContainerFactory.Create();
+
+ if (!await container.ExistsAsync(bucket))
+ {
+ await container.CreateAsync(bucket);
+ }
+
+ string[] testObjects = ["test-object-1", "test-object-2", "test-object-3"];
+ var testContent = "test content".GetBytes();
+ using var stream = new MemoryStream(testContent);
+
+ foreach (var testObject in testObjects)
+ {
+ await container.CreateObjectAsync(
+ new CreateOssObjectRequest(
+ bucket,
+ testObject,
+ stream));
+ }
+
+ await container.BulkDeleteObjectsAsync(
+ new BulkDeleteObjectRequest(bucket, testObjects, "/"));
+
+ var getNotFoundException = await Assert.ThrowsAsync(async () =>
+ await container.GetObjectAsync(
+ new GetOssObjectRequest(
+ bucket,
+ testObjects[0])
+ )
+ );
+
+ getNotFoundException.Code.ShouldBe(OssManagementErrorCodes.ObjectNotFound);
+
+ await container.BulkDeleteObjectsAsync(
+ new BulkDeleteObjectRequest(
+ bucket, testObjects, "/"));
+
+ await container.DeleteAsync(bucket);
+ }
+
+ [Theory]
+ [InlineData("test-bucket")]
+ public async virtual Task Should_List_Object(string bucket)
+ {
+ var container = _ossContainerFactory.Create();
+
+ if (!await container.ExistsAsync(bucket))
+ {
+ await container.CreateAsync(bucket);
+ }
+
+ string[] testObjects = [
+ "test-object-1",
+ "test-object-2",
+ "test-object-3",
+ "test-object-4",
+ "test-object-5"];
+ var testContent = "test content".GetBytes();
+ using var stream = new MemoryStream(testContent);
+
+ foreach (var testObject in testObjects)
+ {
+ await container.CreateObjectAsync(
+ new CreateOssObjectRequest(
+ bucket,
+ testObject,
+ stream));
+ }
+
+ var result1 = await container.GetObjectsAsync(
+ new GetOssObjectsRequest(
+ bucket,
+ "/",
+ maxKeys: 1));
+
+ result1.Objects.Count.ShouldBe(1);
+ result1.Objects[0].Name.ShouldBe(testObjects[0]);
+
+ var result2 = await container.GetObjectsAsync(
+ new GetOssObjectsRequest(
+ bucket,
+ "/",
+ current: 2,
+ maxKeys: 2));
+ result2.Objects.Count.ShouldBe(2);
+ result2.Objects[1].Name.ShouldBe(testObjects[3]);
+
+ await container.BulkDeleteObjectsAsync(
+ new BulkDeleteObjectRequest(
+ bucket, testObjects, "/"));
+
+ await container.DeleteAsync(bucket);
+ }
+}
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN.Abp.OssManagement.Minio.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN.Abp.OssManagement.Minio.Tests.csproj
new file mode 100644
index 000000000..cfc16b8db
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN.Abp.OssManagement.Minio.Tests.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net8.0
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestBase.cs
new file mode 100644
index 000000000..5c2fb9000
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestBase.cs
@@ -0,0 +1,6 @@
+using LINGYUN.Abp.Tests;
+
+namespace LINGYUN.Abp.OssManagement.Minio;
+public abstract class AbpOssManagementMinioTestBase : AbpTestsBase
+{
+}
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestsModule.cs b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestsModule.cs
new file mode 100644
index 000000000..ae534670a
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestsModule.cs
@@ -0,0 +1,43 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.BlobStoring;
+using Volo.Abp.BlobStoring.Minio;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.OssManagement.Minio;
+
+[DependsOn(
+ typeof(AbpOssManagementMinioModule),
+ typeof(AbpOssManagementDomainTestsModule))]
+public class AbpOssManagementMinioTestsModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ var configurationOptions = new AbpConfigurationBuilderOptions
+ {
+ BasePath = @"D:\Projects\Development\Abp\BlobStoring\Minio",
+ EnvironmentName = "Test"
+ };
+
+ context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(configurationOptions));
+ }
+
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ var configuration = context.Services.GetConfiguration();
+
+ Configure(options =>
+ {
+ options.Containers.ConfigureAll((containerName, containerConfiguration) =>
+ {
+ containerConfiguration.UseMinio(minio =>
+ {
+ minio.BucketName = configuration[MinioBlobProviderConfigurationNames.BucketName];
+ minio.AccessKey = configuration[MinioBlobProviderConfigurationNames.AccessKey];
+ minio.SecretKey = configuration[MinioBlobProviderConfigurationNames.SecretKey];
+ minio.EndPoint = configuration[MinioBlobProviderConfigurationNames.EndPoint];
+ });
+ });
+ });
+ }
+}
diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer_Tests.cs
new file mode 100644
index 000000000..f5e342fbe
--- /dev/null
+++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer_Tests.cs
@@ -0,0 +1,4 @@
+namespace LINGYUN.Abp.OssManagement.Minio;
+public class MinioOssContainer_Tests : OssContainer_Tests
+{
+}