mirror of https://github.com/abpframework/abp.git
committed by
GitHub
19 changed files with 662 additions and 11 deletions
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -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> |
||||
@ -0,0 +1,21 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<AssemblyName>Volo.Abp.BlobStoring.Minio</AssemblyName> |
||||
|
<PackageId>Volo.Abp.BlobStoring.Minio</PackageId> |
||||
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" /> |
||||
|
<PackageReference Include="Minio" Version="3.1.13" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Minio |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpBlobStoringModule))] |
||||
|
public class AbpBlobStoringMinioModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -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}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Minio |
||||
|
{ |
||||
|
public interface IMinioBlobNameCalculator |
||||
|
{ |
||||
|
string Calculate(BlobProviderArgs args); |
||||
|
} |
||||
|
} |
||||
@ -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<MinioBlobProviderConfiguration> minioConfigureAction) |
||||
|
{ |
||||
|
containerConfiguration.ProviderType = typeof(MinioBlobProvider); |
||||
|
|
||||
|
minioConfigureAction(new MinioBlobProviderConfiguration(containerConfiguration)); |
||||
|
|
||||
|
return containerConfiguration; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
using System.Text.RegularExpressions; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Minio |
||||
|
{ |
||||
|
public class MinioBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
///https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
|
||||
|
/// </summary>
|
||||
|
public virtual string NormalizeContainerName(string containerName) |
||||
|
{ |
||||
|
// All letters in a container name must be lowercase.
|
||||
|
containerName = containerName.ToLower(); |
||||
|
|
||||
|
// Container names can contain only letters, numbers, and the dash (-) character.
|
||||
|
containerName = Regex.Replace(containerName, "[^a-z0-9-]", string.Empty); |
||||
|
|
||||
|
// Every dash (-) character must be immediately preceded and followed by a letter or number;
|
||||
|
// consecutive dashes are not permitted in container names.
|
||||
|
// Container names must start or end with a letter or number
|
||||
|
containerName = Regex.Replace(containerName, "-{2,}", "-"); |
||||
|
containerName = Regex.Replace(containerName, "^-", string.Empty); |
||||
|
containerName = Regex.Replace(containerName, "-$", string.Empty); |
||||
|
|
||||
|
// Container names must be from 3 through 63 characters long.
|
||||
|
if (containerName.Length < 3) |
||||
|
{ |
||||
|
var length = containerName.Length; |
||||
|
for (var i = 0; i < 3 - length; i++) |
||||
|
{ |
||||
|
containerName += "0"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (containerName.Length > 63) |
||||
|
{ |
||||
|
containerName = containerName.Substring(0, 63); |
||||
|
} |
||||
|
|
||||
|
return containerName; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
|
||||
|
/// </summary>
|
||||
|
public virtual string NormalizeBlobName(string blobName) |
||||
|
{ |
||||
|
return blobName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,145 @@ |
|||||
|
using Minio; |
||||
|
using Minio.Exceptions; |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
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(); |
||||
|
var client = GetMinioClient(args); |
||||
|
var containerName = GetContainerName(args); |
||||
|
|
||||
|
if (!args.OverrideExisting && await BlobExistsAsync(client, containerName, blobName)) |
||||
|
{ |
||||
|
throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{containerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); |
||||
|
} |
||||
|
|
||||
|
if (configuration.CreateBucketIfNotExists) |
||||
|
{ |
||||
|
await CreateBucketIfNotExists(client, containerName); |
||||
|
} |
||||
|
|
||||
|
await client.PutObjectAsync(containerName, blobName, args.BlobStream, args.BlobStream.Length); |
||||
|
} |
||||
|
|
||||
|
public override async Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
||||
|
{ |
||||
|
var blobName = MinioBlobNameCalculator.Calculate(args); |
||||
|
var client = GetMinioClient(args); |
||||
|
var containerName = GetContainerName(args); |
||||
|
|
||||
|
if (await BlobExistsAsync(client, containerName, blobName)) |
||||
|
{ |
||||
|
await client.RemoveObjectAsync(containerName, blobName); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public override async Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
||||
|
{ |
||||
|
var blobName = MinioBlobNameCalculator.Calculate(args); |
||||
|
var client = GetMinioClient(args); |
||||
|
var containerName = GetContainerName(args); |
||||
|
|
||||
|
return await BlobExistsAsync(client, containerName, blobName); |
||||
|
} |
||||
|
|
||||
|
public override async Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) |
||||
|
{ |
||||
|
var blobName = MinioBlobNameCalculator.Calculate(args); |
||||
|
var client = GetMinioClient(args); |
||||
|
var containerName = GetContainerName(args); |
||||
|
|
||||
|
if (!await BlobExistsAsync(client, containerName, blobName)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var memoryStream = new MemoryStream(); |
||||
|
await client.GetObjectAsync(containerName, blobName, stream => |
||||
|
{ |
||||
|
if (stream != null) |
||||
|
{ |
||||
|
stream.CopyTo(memoryStream); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
memoryStream = null; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
return memoryStream; |
||||
|
} |
||||
|
|
||||
|
protected virtual 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(MinioClient client,string containerName) |
||||
|
{ |
||||
|
if (!await client.BucketExistsAsync(containerName)) |
||||
|
{ |
||||
|
await client.MakeBucketAsync(containerName); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private async Task<bool> BlobExistsAsync(MinioClient client, string containerName , string blobName) |
||||
|
{ |
||||
|
// Make sure Blob Container exists.
|
||||
|
if (await client.BucketExistsAsync(containerName)) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
await client.StatObjectAsync(containerName, blobName); |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
if (e is ObjectNotFoundException) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
throw; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
private static string GetContainerName(BlobProviderArgs args) |
||||
|
{ |
||||
|
var configuration = args.Configuration.GetMinioConfiguration(); |
||||
|
|
||||
|
return configuration.BucketName.IsNullOrWhiteSpace() |
||||
|
? args.ContainerName |
||||
|
: configuration.BucketName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
namespace Volo.Abp.BlobStoring.Minio |
||||
|
{ |
||||
|
public class MinioBlobProviderConfiguration |
||||
|
{ |
||||
|
public string BucketName |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfiguration<string>(MinioBlobProviderConfigurationNames.BucketName); |
||||
|
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.BucketName, Check.NotNullOrWhiteSpace(value, nameof(value))); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// endPoint is an URL, domain name, IPv4 address or IPv6 address.
|
||||
|
/// </summary>
|
||||
|
public string EndPoint |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfiguration<string>(MinioBlobProviderConfigurationNames.EndPoint); |
||||
|
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.EndPoint, Check.NotNullOrWhiteSpace(value, nameof(value))); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// accessKey is like user-id that uniquely identifies your account.This field is optional and can be omitted for anonymous access.
|
||||
|
/// </summary>
|
||||
|
public string AccessKey |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfiguration<string>(MinioBlobProviderConfigurationNames.AccessKey); |
||||
|
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.AccessKey, Check.NotNullOrWhiteSpace(value, nameof(value))); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// secretKey is the password to your account.This field is optional and can be omitted for anonymous access.
|
||||
|
/// </summary>
|
||||
|
public string SecretKey |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfiguration<string>(MinioBlobProviderConfigurationNames.SecretKey); |
||||
|
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.SecretKey, Check.NotNullOrWhiteSpace(value, nameof(value))); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
///connect to to MinIO Client object to use https instead of http
|
||||
|
/// </summary>
|
||||
|
public bool WithSSL |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfigurationOrDefault(MinioBlobProviderConfigurationNames.WithSSL, false); |
||||
|
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.WithSSL, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
///Default value: false.
|
||||
|
/// </summary>
|
||||
|
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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<Import Project="..\..\..\common.test.props" /> |
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<UserSecretsId>9f0d2c00-80c1-435b-bfab-2c39c8249091</UserSecretsId> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.BlobStoring.Minio\Volo.Abp.BlobStoring.Minio.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> |
||||
|
<ProjectReference Include="..\Volo.Abp.BlobStoring.Tests\Volo.Abp.BlobStoring.Tests.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Volo.Abp.Testing; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Minio |
||||
|
{ |
||||
|
public class AbpBlobStoringMinioTestCommonBase : AbpIntegratedTest<AbpBlobStoringMinioTestCommonModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class AbpBlobStoringMinioTestBase : AbpIntegratedTest<AbpBlobStoringMinioTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Reactive.Linq; |
||||
|
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<AbpBlobStoringOptions>(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 override async void OnApplicationShutdown(ApplicationShutdownContext context) |
||||
|
{ |
||||
|
var minioClient = new MinioClient(_endPoint, _accessKey, _secretKey); |
||||
|
if (await minioClient.BucketExistsAsync(_randomContainerName)) |
||||
|
{ |
||||
|
var objects = await minioClient.ListObjectsAsync(_randomContainerName, null, true).ToList(); |
||||
|
|
||||
|
foreach (var item in objects) |
||||
|
{ |
||||
|
await minioClient.RemoveObjectAsync(_randomContainerName, item.Key); |
||||
|
} |
||||
|
|
||||
|
await minioClient.RemoveBucketAsync(_randomContainerName); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.BlobStoring.Minio |
||||
|
{ |
||||
|
public class DefaultMinioBlobNamingNormalizerProvider_Tests : AbpBlobStoringMinioTestCommonBase |
||||
|
{ |
||||
|
private readonly IBlobNamingNormalizer _blobNamingNormalizer; |
||||
|
|
||||
|
public DefaultMinioBlobNamingNormalizerProvider_Tests() |
||||
|
{ |
||||
|
_blobNamingNormalizer = GetRequiredService<IBlobNamingNormalizer>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Lowercase() |
||||
|
{ |
||||
|
var filename = "ThisIsMyContainerName"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.ShouldBe("thisismycontainername"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Only_Letters_Numbers_Dash() |
||||
|
{ |
||||
|
var filename = ",./this-i,./s-my-c,./ont,./ai+*/.=!@#$n^&*er-name.+/"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.ShouldBe("this-is-my-container-name"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Dash() |
||||
|
{ |
||||
|
var filename = "-this--is----my-container----name-"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.ShouldBe("this-is-my-container-name"); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Min_Length() |
||||
|
{ |
||||
|
var filename = "a"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.Length.ShouldBeGreaterThanOrEqualTo(3); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
[Fact] |
||||
|
public void NormalizeContainerName_Max_Length() |
||||
|
{ |
||||
|
var filename = "abpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabp"; |
||||
|
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
||||
|
filename.Length.ShouldBeLessThanOrEqualTo(63); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<AbpBlobStoringMinioTestModule> |
||||
|
{ |
||||
|
public MinioBlobContainer_Tests() |
||||
|
{ |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
||||
|
*/ |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
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 MinioSeparator = "/"; |
||||
|
|
||||
|
public MinioBlobNameCalculator_Tests() |
||||
|
{ |
||||
|
_calculator = GetRequiredService<IMinioBlobNameCalculator>(); |
||||
|
_currentTenant = GetRequiredService<ICurrentTenant>(); |
||||
|
} |
||||
|
|
||||
|
[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 |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue