diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index e02d40b1e0..77bb8a2531 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -289,21 +289,25 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.SignalR EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.SignalR.Tests", "test\Volo.Abp.AspNetCore.SignalR.Tests\Volo.Abp.AspNetCore.SignalR.Tests.csproj", "{8B758716-DCC9-4223-8421-5588D1597487}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests", "test\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.csproj", "{79323211-E658-493E-9863-035AA4C3F913}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests", "test\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.csproj", "{79323211-E658-493E-9863-035AA4C3F913}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring", "src\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj", "{A0CFBDD6-A3CB-438C-83F1-5025F12E2D42}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring", "src\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj", "{A0CFBDD6-A3CB-438C-83F1-5025F12E2D42}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Tests", "test\Volo.Abp.BlobStoring.Tests\Volo.Abp.BlobStoring.Tests.csproj", "{D53A17BB-4E23-451D-AD9B-E1F6AC3F7958}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Tests", "test\Volo.Abp.BlobStoring.Tests\Volo.Abp.BlobStoring.Tests.csproj", "{D53A17BB-4E23-451D-AD9B-E1F6AC3F7958}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.FileSystem", "src\Volo.Abp.BlobStoring.FileSystem\Volo.Abp.BlobStoring.FileSystem.csproj", "{02B1FBE2-850E-4612-ABC6-DD62BCF2DD6B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.FileSystem", "src\Volo.Abp.BlobStoring.FileSystem\Volo.Abp.BlobStoring.FileSystem.csproj", "{02B1FBE2-850E-4612-ABC6-DD62BCF2DD6B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.FileSystem.Tests", "test\Volo.Abp.BlobStoring.FileSystem.Tests\Volo.Abp.BlobStoring.FileSystem.Tests.csproj", "{68443D4A-1608-4039-B995-7AF4CF82E9F8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.FileSystem.Tests", "test\Volo.Abp.BlobStoring.FileSystem.Tests\Volo.Abp.BlobStoring.FileSystem.Tests.csproj", "{68443D4A-1608-4039-B995-7AF4CF82E9F8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EntityFrameworkCore.Oracle.Devart", "src\Volo.Abp.EntityFrameworkCore.Oracle.Devart\Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj", "{75E5C841-5F36-4C44-A532-57CB8E7FFE15}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.Oracle.Devart", "src\Volo.Abp.EntityFrameworkCore.Oracle.Devart\Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj", "{75E5C841-5F36-4C44-A532-57CB8E7FFE15}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Azure", "src\Volo.Abp.BlobStoring.Azure\Volo.Abp.BlobStoring.Azure.csproj", "{C44242F7-D55D-4867-AAF4-A786E404312E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Azure", "src\Volo.Abp.BlobStoring.Azure\Volo.Abp.BlobStoring.Azure.csproj", "{C44242F7-D55D-4867-AAF4-A786E404312E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Azure.Tests", "test\Volo.Abp.BlobStoring.Azure.Tests\Volo.Abp.BlobStoring.Azure.Tests.csproj", "{A80E9A0B-8932-4B5D-83FB-6751708FD484}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Azure.Tests", "test\Volo.Abp.BlobStoring.Azure.Tests\Volo.Abp.BlobStoring.Azure.Tests.csproj", "{A80E9A0B-8932-4B5D-83FB-6751708FD484}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Minio", "src\Volo.Abp.BlobStoring.Minio\Volo.Abp.BlobStoring.Minio.csproj", "{658D7EDE-A057-4256-96B6-083D3C2B9704}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Minio.Tests", "test\Volo.Abp.BlobStoring.Minio.Tests\Volo.Abp.BlobStoring.Minio.Tests.csproj", "{36D4B268-FD3A-4655-A41B-D56D68476C83}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -907,6 +911,14 @@ Global {A80E9A0B-8932-4B5D-83FB-6751708FD484}.Debug|Any CPU.Build.0 = Debug|Any CPU {A80E9A0B-8932-4B5D-83FB-6751708FD484}.Release|Any CPU.ActiveCfg = Release|Any CPU {A80E9A0B-8932-4B5D-83FB-6751708FD484}.Release|Any CPU.Build.0 = Release|Any CPU + {658D7EDE-A057-4256-96B6-083D3C2B9704}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {658D7EDE-A057-4256-96B6-083D3C2B9704}.Debug|Any CPU.Build.0 = Debug|Any CPU + {658D7EDE-A057-4256-96B6-083D3C2B9704}.Release|Any CPU.ActiveCfg = Release|Any CPU + {658D7EDE-A057-4256-96B6-083D3C2B9704}.Release|Any CPU.Build.0 = Release|Any CPU + {36D4B268-FD3A-4655-A41B-D56D68476C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36D4B268-FD3A-4655-A41B-D56D68476C83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36D4B268-FD3A-4655-A41B-D56D68476C83}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36D4B268-FD3A-4655-A41B-D56D68476C83}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1061,6 +1073,8 @@ Global {75E5C841-5F36-4C44-A532-57CB8E7FFE15} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {C44242F7-D55D-4867-AAF4-A786E404312E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {A80E9A0B-8932-4B5D-83FB-6751708FD484} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {658D7EDE-A057-4256-96B6-083D3C2B9704} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {36D4B268-FD3A-4655-A41B-D56D68476C83} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/FodyWeavers.xml b/framework/src/Volo.Abp.BlobStoring.Minio/FodyWeavers.xml new file mode 100644 index 0000000000..bc5a74a236 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/FodyWeavers.xsd b/framework/src/Volo.Abp.BlobStoring.Minio/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.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/framework/src/Volo.Abp.BlobStoring.Minio/Volo.Abp.BlobStoring.Minio.csproj b/framework/src/Volo.Abp.BlobStoring.Minio/Volo.Abp.BlobStoring.Minio.csproj new file mode 100644 index 0000000000..1c080067ed --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo.Abp.BlobStoring.Minio.csproj @@ -0,0 +1,21 @@ + + + + + + netstandard2.0 + Volo.Abp.BlobStoring.Minio + Volo.Abp.BlobStoring.Minio + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioModule.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioModule.cs new file mode 100644 index 0000000000..00874dfe01 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioModule.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.BlobStoring.Minio +{ + [DependsOn(typeof(AbpBlobStoringModule))] + public class AbpBlobStoringMinioModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/DefaultMinioBlobNameCalculator.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/DefaultMinioBlobNameCalculator.cs new file mode 100644 index 0000000000..b6d35671e2 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/DefaultMinioBlobNameCalculator.cs @@ -0,0 +1,22 @@ +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.BlobStoring.Minio +{ + public class DefaultMinioBlobNameCalculator : IMinioBlobNameCalculator, ITransientDependency + { + protected ICurrentTenant CurrentTenant { get; } + + public DefaultMinioBlobNameCalculator(ICurrentTenant currentTenant) + { + CurrentTenant = currentTenant; + } + + public virtual string Calculate(BlobProviderArgs args) + { + return CurrentTenant.Id == null + ? $"host/{args.BlobName}" + : $"tenants/{CurrentTenant.Id.Value.ToString("D")}/{args.BlobName}"; + } + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/IMinioBlobNameCalculator.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/IMinioBlobNameCalculator.cs new file mode 100644 index 0000000000..9cf7503648 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/IMinioBlobNameCalculator.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.BlobStoring.Minio +{ + public interface IMinioBlobNameCalculator + { + string Calculate(BlobProviderArgs args); + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobContainerConfigurationExtensions.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobContainerConfigurationExtensions.cs new file mode 100644 index 0000000000..3465914156 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobContainerConfigurationExtensions.cs @@ -0,0 +1,24 @@ +using System; + +namespace Volo.Abp.BlobStoring.Minio +{ + public static class MinioBlobContainerConfigurationExtensions + { + public static MinioBlobProviderConfiguration GetMinioConfiguration( + this BlobContainerConfiguration containerConfiguration) + { + return new MinioBlobProviderConfiguration(containerConfiguration); + } + + public static BlobContainerConfiguration UseMinio( + this BlobContainerConfiguration containerConfiguration, + Action minioConfigureAction) + { + containerConfiguration.ProviderType = typeof(MinioBlobProvider); + + minioConfigureAction(new MinioBlobProviderConfiguration(containerConfiguration)); + + return containerConfiguration; + } + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs new file mode 100644 index 0000000000..a958635f60 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs @@ -0,0 +1,159 @@ +using Minio; +using Minio.Exceptions; +using System; +using System.IO; +using System.Net; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.BlobStoring.Minio +{ + public class MinioBlobProvider : BlobProviderBase, ITransientDependency + { + protected IMinioBlobNameCalculator MinioBlobNameCalculator { get; } + + public MinioBlobProvider(IMinioBlobNameCalculator minioBlobNameCalculator) + { + MinioBlobNameCalculator = minioBlobNameCalculator; + } + + public override async Task SaveAsync(BlobProviderSaveArgs args) + { + var blobName = MinioBlobNameCalculator.Calculate(args); + var configuration = args.Configuration.GetMinioConfiguration(); + + if (!args.OverrideExisting && await BlobExistsAsync(args, blobName)) + { + throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{GetContainerName(args)}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); + } + + if (configuration.CreateBucketIfNotExists) + { + await CreateBucketIfNotExists(args); + } + + await GetMinioClient(args).PutObjectAsync(GetContainerName(args), blobName, args.BlobStream, args.BlobStream.Length); + } + + public override async Task DeleteAsync(BlobProviderDeleteArgs args) + { + var blobName = MinioBlobNameCalculator.Calculate(args); + + if (await BlobExistsAsync(args, blobName)) + { + var client = GetMinioClient(args); + await client.RemoveObjectAsync(GetContainerName(args), blobName); + return true; + } + + return false; + } + + public override async Task ExistsAsync(BlobProviderExistsArgs args) + { + var blobName = MinioBlobNameCalculator.Calculate(args); + + return await BlobExistsAsync(args, blobName); + } + + public override async Task GetOrNullAsync(BlobProviderGetArgs args) + { + var blobName = MinioBlobNameCalculator.Calculate(args); + + if (!await BlobExistsAsync(args, blobName)) + { + return null; + } + try + { + var client = GetMinioClient(args); + + var stat = await client.StatObjectAsync(GetContainerName(args), blobName); + + MemoryStream returnStream = new MemoryStream(); + + await client.GetObjectAsync(GetContainerName(args), blobName, + (stream) => + { + if (stream != null) + { + stream.CopyTo(returnStream); + + // returnStream = new MemoryStream(stream.GetAllBytes()); + + } + }); + + return returnStream; + } + catch (MinioException ex) + { + + } + return null; + + } + + + private MinioClient GetMinioClient(BlobProviderArgs args) + { + var configuration = args.Configuration.GetMinioConfiguration(); + var client = new MinioClient(configuration.EndPoint, configuration.AccessKey, configuration.SecretKey); + if (configuration.WithSSL) + { + client.WithSSL(); + } + + return client; + + } + + + + protected virtual async Task CreateBucketIfNotExists(BlobProviderArgs args) + { + var client = GetMinioClient(args); + var containerName = GetContainerName(args); + if (!await client.BucketExistsAsync(containerName)) + { + await client.MakeBucketAsync(containerName); + } + + } + + private async Task BlobExistsAsync(BlobProviderArgs args, string blobName) + { + // Make sure Blob Container exists. + if (await ContainerExistsAsync(args)) + { + try + { + await GetMinioClient(args).StatObjectAsync(GetContainerName(args), blobName); + return true; + } + catch (MinioException ex) + { + + } + } + return false; + + } + private static string GetContainerName(BlobProviderArgs args) + { + var configuration = args.Configuration.GetMinioConfiguration(); + + //minio bucket name must be lower + return configuration.BucketName.IsNullOrWhiteSpace() + ? args.ContainerName.ToLower() + : configuration.BucketName.ToLower(); + } + + private async Task ContainerExistsAsync(BlobProviderArgs args) + { + var client = GetMinioClient(args); + + return await client.BucketExistsAsync(GetContainerName(args)); + } + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfiguration.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfiguration.cs new file mode 100644 index 0000000000..03e951a984 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfiguration.cs @@ -0,0 +1,65 @@ +namespace Volo.Abp.BlobStoring.Minio +{ + public class MinioBlobProviderConfiguration + { + public string BucketName + { + get => _containerConfiguration.GetConfiguration(MinioBlobProviderConfigurationNames.BucketName); + set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.BucketName, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + + /// + /// endPoint is an URL, domain name, IPv4 address or IPv6 address. + /// + public string EndPoint + { + get => _containerConfiguration.GetConfiguration(MinioBlobProviderConfigurationNames.EndPoint); + set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.EndPoint, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + + /// + /// accessKey is like user-id that uniquely identifies your account.This field is optional and can be omitted for anonymous access. + /// + public string AccessKey + { + get => _containerConfiguration.GetConfiguration(MinioBlobProviderConfigurationNames.AccessKey); + set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.AccessKey, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + + /// + /// secretKey is the password to your account.This field is optional and can be omitted for anonymous access. + /// + public string SecretKey + { + get => _containerConfiguration.GetConfiguration(MinioBlobProviderConfigurationNames.SecretKey); + set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.SecretKey, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + + /// + ///connect to to MinIO Client object to use https instead of http + /// + public bool WithSSL + { + get => _containerConfiguration.GetConfigurationOrDefault(MinioBlobProviderConfigurationNames.WithSSL, false); + set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.WithSSL, value); + } + + + + /// + ///Default value: false. + /// + public bool CreateBucketIfNotExists + { + get => _containerConfiguration.GetConfigurationOrDefault(MinioBlobProviderConfigurationNames.CreateBucketIfNotExists, false); + set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.CreateBucketIfNotExists, value); + } + + private readonly BlobContainerConfiguration _containerConfiguration; + + public MinioBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) + { + _containerConfiguration = containerConfiguration; + } + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfigurationNames.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfigurationNames.cs new file mode 100644 index 0000000000..3c12d98390 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfigurationNames.cs @@ -0,0 +1,12 @@ +namespace Volo.Abp.BlobStoring.Minio +{ + public static class MinioBlobProviderConfigurationNames + { + public const string BucketName = "Minio.BucketName"; + public const string EndPoint = "Minio.EndPoint"; + public const string AccessKey = "Minio.AccessKey"; + public const string SecretKey = "Minio.SecretKey"; + public const string WithSSL = "Minio.WithSSL"; + public const string CreateBucketIfNotExists = "Minio.CreateBucketIfNotExists"; + } +} diff --git a/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo.Abp.BlobStoring.Minio.Tests.csproj b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo.Abp.BlobStoring.Minio.Tests.csproj new file mode 100644 index 0000000000..49f7050734 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo.Abp.BlobStoring.Minio.Tests.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp3.1 + + 9f0d2c00-80c1-435b-bfab-2c39c8249091 + + + + + + + + + + + diff --git a/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioTestBase.cs b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioTestBase.cs new file mode 100644 index 0000000000..c15f093e58 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioTestBase.cs @@ -0,0 +1,20 @@ +using Volo.Abp.Testing; + +namespace Volo.Abp.BlobStoring.Minio +{ + public class AbpBlobStoringMinioTestCommonBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } + + public class AbpBlobStoringMinioTestBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } +} diff --git a/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioTestModule.cs b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioTestModule.cs new file mode 100644 index 0000000000..cfe7b5b4cf --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/AbpBlobStoringMinioTestModule.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Minio; +using Volo.Abp.Modularity; + +namespace Volo.Abp.BlobStoring.Minio +{ + + [DependsOn( + typeof(AbpBlobStoringMinioModule), + typeof(AbpBlobStoringTestModule) + )] + public class AbpBlobStoringMinioTestCommonModule : AbpModule + { + + } + + [DependsOn( + typeof(AbpBlobStoringMinioTestCommonModule) + )] + public class AbpBlobStoringMinioTestModule : AbpModule + { + private const string UserSecretsId = "9f0d2c00-80c1-435b-bfab-2c39c8249091"; + + private string _endPoint; + private string _accessKey; + private string _secretKey; + + + private readonly string _randomContainerName = "abp-minio-test-container-" + Guid.NewGuid().ToString("N"); + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(builderAction: builder => + { + builder.AddUserSecrets(UserSecretsId); + })); + + var configuration = context.Services.GetConfiguration(); + _endPoint = configuration["Minio:EndPoint"]; + _accessKey = configuration["Minio:AccessKey"]; + _secretKey = configuration["Minio:SecretKey"]; + + Configure(options => + { + options.Containers.ConfigureAll((containerName, containerConfiguration) => + { + containerConfiguration.UseMinio(minio => + { + minio.EndPoint = _endPoint; + minio.AccessKey = _accessKey; + minio.SecretKey = _secretKey; + minio.WithSSL = false; + minio.BucketName = _randomContainerName; + minio.CreateBucketIfNotExists = true; + }); + }); + }); + } + + public async override void OnApplicationShutdown(ApplicationShutdownContext context) + { + var minioClient = new MinioClient(_endPoint, _accessKey, _secretKey); + if (await minioClient.BucketExistsAsync(_randomContainerName)) + { + var observables =minioClient.ListObjectsAsync(_randomContainerName,null,true); + var objectNames = new List(); + IDisposable subscription = observables.Subscribe( + async item => await minioClient.RemoveObjectAsync(_randomContainerName, item.Key), + async () => await minioClient.RemoveBucketAsync(_randomContainerName) + ); + + } + + } + } + +} diff --git a/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/MinioBlobContainer_Tests.cs b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/MinioBlobContainer_Tests.cs new file mode 100644 index 0000000000..5c38b098d5 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/MinioBlobContainer_Tests.cs @@ -0,0 +1,16 @@ +using Xunit; + +namespace Volo.Abp.BlobStoring.Minio +{ + + ////Please set the correct connection string in secrets.json and continue the test. + + //public class MinioBlobContainer_Tests : BlobContainer_Tests + //{ + // public MinioBlobContainer_Tests() + // { + + // } + //} + +} diff --git a/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/MinioBlobNameCalculator_Tests.cs b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/MinioBlobNameCalculator_Tests.cs new file mode 100644 index 0000000000..712c849965 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Minio.Tests/Volo/Abp/BlobStoring/Minio/MinioBlobNameCalculator_Tests.cs @@ -0,0 +1,57 @@ +using System; +using Shouldly; +using Volo.Abp.MultiTenancy; +using Xunit; + +namespace Volo.Abp.BlobStoring.Minio +{ + public class MinioBlobNameCalculator_Tests : AbpBlobStoringMinioTestCommonBase + { + private readonly IMinioBlobNameCalculator _calculator; + private readonly ICurrentTenant _currentTenant; + + private const string MinioContainerName = "/"; + private const string MinioSeparator = "/"; + + public MinioBlobNameCalculator_Tests() + { + _calculator = GetRequiredService(); + _currentTenant = GetRequiredService(); + } + + [Fact] + public void Default_Settings() + { + _calculator.Calculate( + GetArgs("my-container", "my-blob") + ).ShouldBe($"host{MinioSeparator}my-blob"); + } + + [Fact] + public void Default_Settings_With_TenantId() + { + var tenantId = Guid.NewGuid(); + + using (_currentTenant.Change(tenantId)) + { + _calculator.Calculate( + GetArgs("my-container", "my-blob") + ).ShouldBe($"tenants{MinioSeparator}{tenantId:D}{MinioSeparator}my-blob"); + } + } + + private static BlobProviderArgs GetArgs( + string containerName, + string blobName) + { + return new BlobProviderGetArgs( + containerName, + new BlobContainerConfiguration().UseMinio(x => + { + x.BucketName = containerName; + }), + blobName + ); + } + } +}