Browse Source

Merge pull request #1021 from colinin/oss-minio

feat(oss-management): add oss module Minio implementation
pull/1050/head
yx lin 1 year ago
committed by GitHub
parent
commit
826a6dea54
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 25
      aspnet-core/LINGYUN.MicroService.All.sln
  2. 17
      aspnet-core/LINGYUN.MicroService.SingleProject.sln
  3. 6
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs
  4. 2
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementContainer.cs
  5. 4
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/IOssContainer.cs
  6. 4
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/OssObjectAcknowledgeHandler.cs
  7. 3
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xml
  8. 30
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xsd
  9. 24
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN.Abp.OssManagement.Minio.csproj
  10. 23
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioModule.cs
  11. 558
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer.cs
  12. 44
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN/Abp/OssManagement/Minio/MinioOssContainerFactory.cs
  13. 19
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/README.md
  14. 6
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Nexus/LINGYUN/Abp/OssManagement/Nexus/NexusOssContainer.cs
  15. 5
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Tencent/LINGYUN/Abp/OssManagement/Tencent/TencentOssContainer.cs
  16. 1
      aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
  17. 13
      aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
  18. 10
      aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
  19. 8
      aspnet-core/services/LY.MicroService.Applications.Single/appsettings.Development.json
  20. 23
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN.Abp.OssManagement.Domain.Tests.csproj
  21. 6
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestBase.cs
  22. 11
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementDomainTestsModule.cs
  23. 248
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN/Abp/OssManagement/OssContainer_Tests.cs
  24. 23
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN.Abp.OssManagement.Minio.Tests.csproj
  25. 6
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestBase.cs
  26. 43
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/AbpOssManagementMinioTestsModule.cs
  27. 4
      aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN/Abp/OssManagement/Minio/MinioOssContainer_Tests.cs

25
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}

17
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}

6
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs

@ -130,10 +130,12 @@ internal class AliyunOssContainer : IOssContainer, IOssObjectExpireor
// 阿里云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)

2
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
{
}

4
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/IOssContainer.cs

@ -36,6 +36,10 @@ public interface IOssContainer
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
/// <exception cref="Volo.Abp.BusinessException">
/// When the bucket does not exist, an exception is thrown with the error code is
/// <see cref="OssManagementErrorCodes.ContainerDeleteWithNotEmpty"/>
/// </exception>
Task DeleteAsync(string name);
/// <summary>
/// 删除Oss对象

4
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/OssObjectAcknowledgeHandler.cs

@ -22,9 +22,9 @@ public class OssObjectAcknowledgeHandler : IDistributedEventHandler<OssObjectAck
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)
{

3
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

24
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Minio/LINGYUN.Abp.OssManagement.Minio.csproj

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>LINGYUN.Abp.OssManagement.Minio</AssemblyName>
<PackageId>LINGYUN.Abp.OssManagement.Minio</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.BlobStoring.Minio" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Domain\LINGYUN.Abp.OssManagement.Domain.csproj" />
</ItemGroup>
</Project>

23
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<IOssContainerFactory, MinioOssContainerFactory>();
context.Services.AddTransient<IOssObjectExpireor>(provider =>
provider
.GetRequiredService<IOssContainerFactory>()
.Create()
.As<MinioOssContainer>());
}
}

558
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;
/// <summary>
/// Oss容器的Minio实现
/// </summary>
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<MinioOssContainer> Logger { get; }
public MinioOssContainer(
IClock clock,
ICurrentTenant currentTenant,
ILogger<MinioOssContainer> 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<bool>();
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<OssContainer> 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<string, string>());
}
public async virtual Task<OssObject> 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<string, string>(),
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<bool>();
var listObjectObs = client.ListObjectsAsync(
new ListObjectsArgs()
.WithBucket(bucket));
var listObjects = new List<string>();
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<bool> 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<bool>();
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<OssContainer> 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<string, string>());
}
public async virtual Task<GetOssContainersResponse> 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<string, string>()))
.ToList();
return new GetOssContainersResponse(
request.Prefix,
request.Marker,
null,
totalCount,
resultObjects);
}
public async virtual Task<OssObject> 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<GetOssObjectsResponse> 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<bool>();
var listObjectResult = client.ListObjectsAsync(listObjectArgs);
var resultObjects = new List<OssObject>();
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<long>(),
item.LastModifiedDateTime,
new Dictionary<string, string>(),
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<bool> BucketExists(IMinioClient client, string bucket)
{
var args = new BucketExistsArgs().WithBucket(bucket);
return await client.BucketExistsAsync(args);
}
protected async virtual Task<bool> 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<AbpOssManagementContainer>();
return configuration.GetMinioConfiguration();
}
protected virtual string GetBucket(string bucket)
{
var configuration = ConfigurationProvider.Get<AbpOssManagementContainer>();
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("//", "");
}
}

44
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<MinioOssContainer> Logger { get; }
public MinioOssContainerFactory(
IClock clock,
ICurrentTenant currentTenant,
ILogger<MinioOssContainer> 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);
}
}

19
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
}
```

6
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Nexus/LINGYUN/Abp/OssManagement/Nexus/NexusOssContainer.cs

@ -118,10 +118,12 @@ internal class NexusOssContainer : IOssContainer, IOssObjectExpireor
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)

5
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Tencent/LINGYUN/Abp/OssManagement/Tencent/TencentOssContainer.cs

@ -151,12 +151,13 @@ internal class TencentOssContainer : IOssContainer, IOssObjectExpireor
// 阿里云oss在控制台设置即可,无需改变
var ossClient = await CreateClientAsync();
if (BucketExists(ossClient, name))
if (!BucketExists(ossClient, name))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
}
var deleteBucketRequest = new DeleteBucketRequest(name);
ossClient.DeleteBucket(deleteBucketRequest);
}
}
public async virtual Task ExpireAsync(ExprieOssObjectRequest request)
{

1
aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj

@ -205,6 +205,7 @@
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.Domain\LINGYUN.Abp.OssManagement.Domain.csproj" />
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.FileSystem.ImageSharp\LINGYUN.Abp.OssManagement.FileSystem.ImageSharp.csproj" />
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.FileSystem\LINGYUN.Abp.OssManagement.FileSystem.csproj" />
<!--<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.Minio\LINGYUN.Abp.OssManagement.Minio.csproj" />-->
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.HttpApi\LINGYUN.Abp.OssManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.SettingManagement\LINGYUN.Abp.OssManagement.SettingManagement.csproj" />
<ProjectReference Include="..\..\modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application\LINGYUN.Abp.PermissionManagement.Application.csproj" />

13
aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs

@ -386,7 +386,7 @@ public partial class MicroServiceApplicationsSingleModule
});
}
private void ConfigureBlobStoring()
private void ConfigureBlobStoring(IConfiguration configuration)
{
Configure<AbpBlobStoringOptions>(options =>
{
@ -396,6 +396,11 @@ public partial class MicroServiceApplicationsSingleModule
{
fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "blobs");
});
//containerConfiguration.UseMinio(minio =>
//{
// configuration.GetSection("Minio").Bind(minio);
//});
});
});
}
@ -405,9 +410,9 @@ public partial class MicroServiceApplicationsSingleModule
Configure<AbpBackgroundTasksOptions>(options =>
{
options.NodeName = ApplicationName;
options.JobCleanEnabled = false;
options.JobFetchEnabled = false;
options.JobCheckEnabled = false;
options.JobCleanEnabled = true;
options.JobFetchEnabled = true;
options.JobCheckEnabled = true;
});
}

10
aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs

@ -45,9 +45,6 @@ using LINGYUN.Abp.Identity.Notifications;
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.HttpApi;
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.Modularity;
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 partial class MicroServiceApplicationsSingleModule : AbpModule
ConfigureIdempotent();
ConfigureMvcUiTheme();
ConfigureDataSeeder();
ConfigureBlobStoring();
ConfigureLocalization();
ConfigureKestrelServer();
ConfigureBackgroundTasks();
@ -365,6 +360,7 @@ public partial class MicroServiceApplicationsSingleModule : AbpModule
ConfigureAuthServer(configuration);
ConfigureSwagger(context.Services);
ConfigureEndpoints(context.Services);
ConfigureBlobStoring(configuration);
ConfigureMultiTenancy(configuration);
ConfigureJsonSerializer(configuration);
ConfigureTextTemplating(configuration);

8
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",

23
aspnet-core/tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN.Abp.OssManagement.Domain.Tests.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace />
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.Domain\LINGYUN.Abp.OssManagement.Domain.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" />
</ItemGroup>
</Project>

6
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<AbpOssManagementDomainTestsModule>
{
}

11
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
{
}

248
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<TStartupModule> : AbpIntegratedTest<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly ICurrentTenant _currentTenant;
private readonly IOssContainerFactory _ossContainerFactory;
protected OssContainer_Tests()
{
_currentTenant = GetRequiredService<ICurrentTenant>();
_ossContainerFactory = GetRequiredService<IOssContainerFactory>();
}
[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<BusinessException>(async () =>
await container.GetAsync(bucket)
);
getNotFoundException.Code.ShouldBe(OssManagementErrorCodes.ContainerNotFound);
var deleteNotFoundException = await Assert.ThrowsAsync<BusinessException>(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<BusinessException>(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<BusinessException>(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);
}
}

23
aspnet-core/tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN.Abp.OssManagement.Minio.Tests.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace />
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.Minio\LINGYUN.Abp.OssManagement.Minio.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Domain.Tests\LINGYUN.Abp.OssManagement.Domain.Tests.csproj" />
</ItemGroup>
</Project>

6
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<AbpOssManagementMinioTestsModule>
{
}

43
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<AbpBlobStoringOptions>(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];
});
});
});
}
}

4
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<AbpOssManagementMinioTestsModule>
{
}
Loading…
Cancel
Save