diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 1c8e0baeca..5778b054ed 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -321,6 +321,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Aliyun EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Aws", "src\Volo.Abp.BlobStoring.Aws\Volo.Abp.BlobStoring.Aws.csproj", "{50968CDE-1029-4051-B2E5-B69D0ECF2A18}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Aws.Tests", "test\Volo.Abp.BlobStoring.Aws.Tests\Volo.Abp.BlobStoring.Aws.Tests.csproj", "{2CD3B26A-CA81-4279-8D5D-6A594517BB3F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -955,6 +957,10 @@ Global {50968CDE-1029-4051-B2E5-B69D0ECF2A18}.Debug|Any CPU.Build.0 = Debug|Any CPU {50968CDE-1029-4051-B2E5-B69D0ECF2A18}.Release|Any CPU.ActiveCfg = Release|Any CPU {50968CDE-1029-4051-B2E5-B69D0ECF2A18}.Release|Any CPU.Build.0 = Release|Any CPU + {2CD3B26A-CA81-4279-8D5D-6A594517BB3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2CD3B26A-CA81-4279-8D5D-6A594517BB3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CD3B26A-CA81-4279-8D5D-6A594517BB3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2CD3B26A-CA81-4279-8D5D-6A594517BB3F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1117,6 +1123,7 @@ Global {845E6A13-D1B5-4DDC-A16C-68D807E3B4C7} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {8E49687A-E69F-49F2-8DB0-428D0883A937} = {447C8A77-E5F0-4538-8687-7383196D04EA} {50968CDE-1029-4051-B2E5-B69D0ECF2A18} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {2CD3B26A-CA81-4279-8D5D-6A594517BB3F} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsModule.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsModule.cs new file mode 100644 index 0000000000..84a18a5ca9 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Caching; +using Volo.Abp.Modularity; + +namespace Volo.Abp.BlobStoring.Aws +{ + [DependsOn(typeof(AbpBlobStoringModule), + typeof(AbpCachingModule))] + public class AbpBlobStoringAwsModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAzureModule.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAzureModule.cs deleted file mode 100644 index 0b386fbec1..0000000000 --- a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAzureModule.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Volo.Abp.Modularity; - -namespace Volo.Abp.BlobStoring.Azure -{ - [DependsOn(typeof(AbpBlobStoringModule))] - public class AbpBlobStoringAzureModule : AbpModule - { - - } -} diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs index 17831b6f4b..6acb91aea9 100644 --- a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs @@ -36,7 +36,7 @@ namespace Volo.Abp.BlobStoring.Aws if (configuration.CreateContainerIfNotExists) { - await amazonS3Client.PutBucketAsync(containerName); + await CreateContainerIfNotExists(amazonS3Client, containerName); } await amazonS3Client.PutObjectAsync(new PutObjectRequest @@ -108,7 +108,6 @@ namespace Volo.Abp.BlobStoring.Aws protected virtual async Task GetAmazonS3Client(BlobProviderArgs args) { var configuration = args.Configuration.GetAwsConfiguration(); - return await AmazonS3ClientFactory.GetAmazonS3Client(configuration); } @@ -137,6 +136,17 @@ namespace Volo.Abp.BlobStoring.Aws return true; } + protected virtual async Task CreateContainerIfNotExists(AmazonS3Client amazonS3Client, string containerName) + { + if (!await AmazonS3Util.DoesS3BucketExistV2Async(amazonS3Client, containerName)) + { + await amazonS3Client.PutBucketAsync(new PutBucketRequest + { + BucketName = containerName + }); + } + } + private static string GetContainerName(BlobProviderArgs args) { var configuration = args.Configuration.GetAwsConfiguration(); diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs index fde0f10fc9..62695610ff 100644 --- a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs @@ -9,43 +9,43 @@ namespace Volo.Abp.BlobStoring.Aws { public string AccessKeyId { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.AccessKeyId); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.AccessKeyId); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.AccessKeyId, value); } public string SecretAccessKey { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.SecretAccessKey); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.SecretAccessKey); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.SecretAccessKey, value); } - public bool UseAwsCredentials + public bool UseCredentials { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.UseAwsCredentials); - set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.UseAwsCredentials, value); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.UseCredentials,false); + set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.UseCredentials, value); } public bool UseTemporaryCredentials { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.UseTemporaryCredentials); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.UseTemporaryCredentials,false); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.UseTemporaryCredentials, value); } public bool UseTemporaryFederatedCredentials { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.UseTemporaryFederatedCredentials); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.UseTemporaryFederatedCredentials,false); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.UseTemporaryFederatedCredentials, value); } public string ProfileName { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.ProfileName); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.ProfileName); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.ProfileName, value); } public string ProfilesLocation { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.ProfilesLocation); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.ProfilesLocation); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.ProfilesLocation, value); } @@ -66,13 +66,13 @@ namespace Volo.Abp.BlobStoring.Aws public string Policy { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.Policy); + get => _containerConfiguration.GetConfigurationOrDefault(AwsBlobProviderConfigurationNames.Policy); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.Policy, value); } - public RegionEndpoint Region + public string Region { - get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.Region); + get => _containerConfiguration.GetConfiguration(AwsBlobProviderConfigurationNames.Region); set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.Region, Check.NotNull(value, nameof(value))); } diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfigurationNames.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfigurationNames.cs index f27efc1552..600aab5bd7 100644 --- a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfigurationNames.cs +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfigurationNames.cs @@ -4,7 +4,7 @@ { public const string AccessKeyId = "Aws.AccessKeyId"; public const string SecretAccessKey = "Aws.SecretAccessKey"; - public const string UseAwsCredentials = "Aws.UseAWSCredentials"; + public const string UseCredentials = "Aws.UseCredentials"; public const string UseTemporaryCredentials = "Aws.UseTemporaryCredentials"; public const string UseTemporaryFederatedCredentials = "Aws.UseTemporaryFederatedCredentials"; public const string ProfileName = "Aws.ProfileName"; diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AssumeRoleCredentialsCacheItem.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsTemporaryCredentialsCacheItem.cs similarity index 55% rename from framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AssumeRoleCredentialsCacheItem.cs rename to framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsTemporaryCredentialsCacheItem.cs index dbc4783978..d45cb2d958 100644 --- a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AssumeRoleCredentialsCacheItem.cs +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsTemporaryCredentialsCacheItem.cs @@ -1,13 +1,11 @@ using System; -using Volo.Abp.Caching; namespace Volo.Abp.BlobStoring.Aws { [Serializable] - [CacheName("TemporaryCredentials")] - public class TemporaryCredentialsCacheItem + public class AwsTemporaryCredentialsCacheItem { - public const string Key = "AwsTemporaryCredentialsCache"; + public const string Key = "AwsBlobTemporaryCredentialsCache"; public string AccessKeyId { get; set; } @@ -15,12 +13,12 @@ namespace Volo.Abp.BlobStoring.Aws public string SessionToken { get; set; } - public TemporaryCredentialsCacheItem() + public AwsTemporaryCredentialsCacheItem() { } - public TemporaryCredentialsCacheItem(string accessKeyId,string secretAccessKey,string sessionToken) + public AwsTemporaryCredentialsCacheItem(string accessKeyId,string secretAccessKey,string sessionToken) { AccessKeyId = accessKeyId; SecretAccessKey = secretAccessKey; diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/DefaultAmazonS3ClientFactory.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/DefaultAmazonS3ClientFactory.cs index febda577fc..7ae6e4c004 100644 --- a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/DefaultAmazonS3ClientFactory.cs +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/DefaultAmazonS3ClientFactory.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Amazon; using Amazon.Runtime; using Amazon.Runtime.CredentialManagement; using Amazon.S3; @@ -13,9 +14,9 @@ namespace Volo.Abp.BlobStoring.Aws { public class DefaultAmazonS3ClientFactory : IAmazonS3ClientFactory, ITransientDependency { - protected IDistributedCache Cache { get; } + protected IDistributedCache Cache { get; } - public DefaultAmazonS3ClientFactory(IDistributedCache cache) + public DefaultAmazonS3ClientFactory(IDistributedCache cache) { Cache = cache; } @@ -23,31 +24,41 @@ namespace Volo.Abp.BlobStoring.Aws public virtual async Task GetAmazonS3Client( AwsBlobProviderConfiguration configuration) { - if (configuration.UseAwsCredentials) + var region = RegionEndpoint.GetBySystemName(configuration.Region); + + if (configuration.UseCredentials) { - return new AmazonS3Client(GetAwsCredentials(configuration), configuration.Region); + var awsCredentials = GetAwsCredentials(configuration); + return awsCredentials == null + ? new AmazonS3Client(region) + : new AmazonS3Client(GetAwsCredentials(configuration), region); } if (configuration.UseTemporaryCredentials) { - return new AmazonS3Client(await GetTemporaryCredentialsAsync(configuration), configuration.Region); + return new AmazonS3Client(await GetTemporaryCredentialsAsync(configuration), region); } if (configuration.UseTemporaryFederatedCredentials) { return new AmazonS3Client(await GetTemporaryFederatedCredentialsAsync(configuration), - configuration.Region); + region); } Check.NotNullOrWhiteSpace(configuration.AccessKeyId, nameof(configuration.AccessKeyId)); Check.NotNullOrWhiteSpace(configuration.SecretAccessKey, nameof(configuration.SecretAccessKey)); - return new AmazonS3Client(configuration.AccessKeyId, configuration.SecretAccessKey); + return new AmazonS3Client(configuration.AccessKeyId, configuration.SecretAccessKey, configuration.Region); } protected virtual AWSCredentials GetAwsCredentials( AwsBlobProviderConfiguration configuration) { + if (configuration.ProfileName.IsNullOrWhiteSpace()) + { + return null; + } + var chain = new CredentialProfileStoreChain(configuration.ProfilesLocation); if (chain.TryGetAWSCredentials(configuration.ProfileName, out var awsCredentials)) @@ -61,7 +72,7 @@ namespace Volo.Abp.BlobStoring.Aws protected virtual async Task GetTemporaryCredentialsAsync( AwsBlobProviderConfiguration configuration) { - var temporaryCredentialsCache = await Cache.GetAsync(TemporaryCredentialsCacheItem.Key); + var temporaryCredentialsCache = await Cache.GetAsync(AwsTemporaryCredentialsCacheItem.Key); if (temporaryCredentialsCache == null) { @@ -74,7 +85,10 @@ namespace Volo.Abp.BlobStoring.Aws } else { - stsClient = new AmazonSecurityTokenServiceClient(GetAwsCredentials(configuration)); + var awsCredentials = GetAwsCredentials(configuration); + stsClient = awsCredentials == null + ? new AmazonSecurityTokenServiceClient() + : new AmazonSecurityTokenServiceClient(awsCredentials); } using (stsClient) @@ -105,8 +119,9 @@ namespace Volo.Abp.BlobStoring.Aws AwsBlobProviderConfiguration configuration) { Check.NotNullOrWhiteSpace(configuration.Name, nameof(configuration.Name)); + Check.NotNullOrWhiteSpace(configuration.Policy, nameof(configuration.Policy)); - var temporaryCredentialsCache = await Cache.GetAsync(TemporaryCredentialsCacheItem.Key); + var temporaryCredentialsCache = await Cache.GetAsync(AwsTemporaryCredentialsCacheItem.Key); if (temporaryCredentialsCache == null) { @@ -119,7 +134,10 @@ namespace Volo.Abp.BlobStoring.Aws } else { - stsClient = new AmazonSecurityTokenServiceClient(GetAwsCredentials(configuration)); + var awsCredentials = GetAwsCredentials(configuration); + stsClient = awsCredentials == null + ? new AmazonSecurityTokenServiceClient() + : new AmazonSecurityTokenServiceClient(awsCredentials); } using (stsClient) @@ -148,15 +166,15 @@ namespace Volo.Abp.BlobStoring.Aws return sessionCredentials; } - private async Task SetTemporaryCredentialsCache( + private async Task SetTemporaryCredentialsCache( Credentials credentials, int durationSeconds) { - var temporaryCredentialsCache = new TemporaryCredentialsCacheItem(credentials.AccessKeyId, + var temporaryCredentialsCache = new AwsTemporaryCredentialsCacheItem(credentials.AccessKeyId, credentials.SecretAccessKey, credentials.SessionToken); - await Cache.SetAsync(TemporaryCredentialsCacheItem.Key, temporaryCredentialsCache, + await Cache.SetAsync(AwsTemporaryCredentialsCacheItem.Key, temporaryCredentialsCache, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(durationSeconds - 10) diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/DefaultAwsBlobNameCalculator.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/DefaultAwsBlobNameCalculator.cs new file mode 100644 index 0000000000..9ff3511e6f --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/DefaultAwsBlobNameCalculator.cs @@ -0,0 +1,22 @@ +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.BlobStoring.Aws +{ + public class DefaultAwsBlobNameCalculator : IAwsBlobNameCalculator, ITransientDependency + { + protected ICurrentTenant CurrentTenant { get; } + + public DefaultAwsBlobNameCalculator(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/test/Volo.Abp.BlobStoring.Aws.Tests/Volo.Abp.BlobStoring.Aws.Tests.csproj b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo.Abp.BlobStoring.Aws.Tests.csproj new file mode 100644 index 0000000000..2a4910e32c --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo.Abp.BlobStoring.Aws.Tests.csproj @@ -0,0 +1,19 @@ + + + + + + netcoreapp3.1 + + 9f0d2c00-80c1-435b-bfab-2c39c8249091 + + + + + + + + + + + diff --git a/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestBase.cs b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestBase.cs new file mode 100644 index 0000000000..eef12cb0a1 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestBase.cs @@ -0,0 +1,20 @@ +using Volo.Abp.Testing; + +namespace Volo.Abp.BlobStoring.Aws +{ + public class AbpBlobStoringAwsTestCommonBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } + + public class AbpBlobStoringAwsTestBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } +} diff --git a/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestModule.cs b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestModule.cs new file mode 100644 index 0000000000..dc9dda1b76 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestModule.cs @@ -0,0 +1,91 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Amazon.S3.Model; +using Amazon.S3.Util; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; +using Volo.Abp.Threading; + +namespace Volo.Abp.BlobStoring.Aws +{ + /// + /// This module will not try to connect to aws. + /// + [DependsOn( + typeof(AbpBlobStoringAwsModule), + typeof(AbpBlobStoringTestModule) + )] + public class AbpBlobStoringAwsTestCommonModule : AbpModule + { + } + + [DependsOn( + typeof(AbpBlobStoringAwsTestCommonModule) + )] + public class AbpBlobStoringAwsTestModule : AbpModule + { + private const string UserSecretsId = "9f0d2c00-80c1-435b-bfab-2c39c8249091"; + + private readonly string _randomContainerName = "abp-aws-test-container-" + Guid.NewGuid().ToString("N"); + + private AwsBlobProviderConfiguration _configuration; + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(builderAction: builder => + { + builder.AddUserSecrets(UserSecretsId); + })); + + var configuration = context.Services.GetConfiguration(); + var accessKeyId = configuration["Aws:AccessKeyId"]; + var secretAccessKey = configuration["Aws:SecretAccessKey"]; + var region = configuration["Aws:Region"]; + + Configure(options => + { + options.Containers.ConfigureAll((containerName, containerConfiguration) => + { + containerConfiguration.UseAws(aws => + { + aws.AccessKeyId = accessKeyId; + aws.SecretAccessKey = secretAccessKey; + aws.Region = region; + aws.CreateContainerIfNotExists = true; + + _configuration = aws; + }); + }); + }); + } + + public override void OnApplicationShutdown(ApplicationShutdownContext context) + { + AsyncHelper.RunSync(() => DeleteBucketAsync(context)); + } + + private async Task DeleteBucketAsync(ApplicationShutdownContext context) + { + var amazonS3Client = await context.ServiceProvider.GetService() + .GetAmazonS3Client(_configuration); + + if (await AmazonS3Util.DoesS3BucketExistV2Async(amazonS3Client, _randomContainerName)) + { + var blobs = await amazonS3Client.ListObjectsAsync(_randomContainerName); + + if (blobs.S3Objects.Any()) + { + await amazonS3Client.DeleteObjectsAsync(new DeleteObjectsRequest + { + BucketName = _randomContainerName, + Objects = blobs.S3Objects.Select(o => new KeyVersion {Key = o.Key}).ToList() + }); + } + + await amazonS3Client.DeleteBucketAsync(_randomContainerName); + } + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AwsBlobContainer_Tests.cs b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AwsBlobContainer_Tests.cs new file mode 100644 index 0000000000..662949e7e3 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AwsBlobContainer_Tests.cs @@ -0,0 +1,16 @@ +using Xunit; + +namespace Volo.Abp.BlobStoring.Aws +{ + /* + //Please set the correct connection string in secrets.json and continue the test. + + public class AwsBlobContainer_Tests : BlobContainer_Tests + { + public AwsBlobContainer_Tests() + { + + } + } + */ +} diff --git a/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AwsBlobNameCalculator_Tests.cs b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AwsBlobNameCalculator_Tests.cs new file mode 100644 index 0000000000..e4fbe714f8 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AwsBlobNameCalculator_Tests.cs @@ -0,0 +1,57 @@ +using System; +using Shouldly; +using Volo.Abp.MultiTenancy; +using Xunit; + +namespace Volo.Abp.BlobStoring.Aws +{ + public class AwsBlobNameCalculatorTests : AbpBlobStoringAwsTestCommonBase + { + private readonly IAwsBlobNameCalculator _calculator; + private readonly ICurrentTenant _currentTenant; + + private const string AwsContainerName = "/"; + private const string AwsSeparator = "/"; + + public AwsBlobNameCalculatorTests() + { + _calculator = GetRequiredService(); + _currentTenant = GetRequiredService(); + } + + [Fact] + public void Default_Settings() + { + _calculator.Calculate( + GetArgs("my-container", "my-blob") + ).ShouldBe($"host{AwsSeparator}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{AwsSeparator}{tenantId:D}{AwsSeparator}my-blob"); + } + } + + private static BlobProviderArgs GetArgs( + string containerName, + string blobName) + { + return new BlobProviderGetArgs( + containerName, + new BlobContainerConfiguration().UseAws(x => + { + x.ContainerName = containerName; + }), + blobName + ); + } + } +} diff --git a/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/DefaultAwsBlobNamingNormalizerProvider_Tests.cs b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/DefaultAwsBlobNamingNormalizerProvider_Tests.cs new file mode 100644 index 0000000000..7798c52419 --- /dev/null +++ b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/DefaultAwsBlobNamingNormalizerProvider_Tests.cs @@ -0,0 +1,57 @@ +using Shouldly; +using Xunit; + +namespace Volo.Abp.BlobStoring.Aws +{ + public class DefaultAwsBlobNamingNormalizerProviderTests : AbpBlobStoringAwsTestCommonBase + { + private readonly IBlobNamingNormalizer _blobNamingNormalizer; + + public DefaultAwsBlobNamingNormalizerProviderTests() + { + _blobNamingNormalizer = GetRequiredService(); + } + + [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); + } + } +}