23 changed files with 695 additions and 12 deletions
@ -0,0 +1,12 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Core" Version="2.9.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Aliyun.Authorization |
||||
|
{ |
||||
|
public class AbpAliyunAuthorizationModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
|
||||
|
Configure<AbpAliyunOptions>(configuration.GetSection("Aliyun:Auth")); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace LINGYUN.Abp.Aliyun.Authorization |
||||
|
{ |
||||
|
public class AbpAliyunOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 访问标识
|
||||
|
/// </summary>
|
||||
|
public string AccessKeyId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 访问密钥
|
||||
|
/// </summary>
|
||||
|
public string AccessKeySecret { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> |
||||
|
<Version>2.9.0</Version> |
||||
|
<Authors>LINGYUN</Authors> |
||||
|
<Description>阿里云Oss对象存储Abp集成</Description> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
||||
|
<OutputPath>D:\LocalNuget</OutputPath> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.10.0" /> |
||||
|
<PackageReference Include="Volo.Abp.BlobStoring" Version="2.9.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Aliyun.Authorization\LINGYUN.Abp.Aliyun.Authorization.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,35 @@ |
|||||
|
using LINGYUN.Abp.Aliyun.Authorization; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpBlobStoringModule), |
||||
|
typeof(AbpAliyunAuthorizationModule))] |
||||
|
public class AbpBlobStoringAliyunModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
|
||||
|
Configure<AbpBlobStoringOptions>(options => |
||||
|
{ |
||||
|
context.Services.ExecutePreConfiguredActions(options); |
||||
|
options.Containers.ConfigureAll((containerName, containerConfiguration) => |
||||
|
{ |
||||
|
containerConfiguration.UseAliyun(aliyun => |
||||
|
{ |
||||
|
aliyun.BucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName]; |
||||
|
aliyun.CreateBucketIfNotExists = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists).Get<bool>(); |
||||
|
aliyun.CreateBucketReferer = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketReferer).Get<List<string>>(); |
||||
|
aliyun.Endpoint = configuration[AliyunBlobProviderConfigurationNames.Endpoint]; |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public static class AliyunBlobContainerConfigurationExtensions |
||||
|
{ |
||||
|
public static AliyunBlobProviderConfiguration GetAliyunConfiguration( |
||||
|
this BlobContainerConfiguration containerConfiguration) |
||||
|
{ |
||||
|
return new AliyunBlobProviderConfiguration(containerConfiguration); |
||||
|
} |
||||
|
|
||||
|
public static BlobContainerConfiguration UseAliyun( |
||||
|
this BlobContainerConfiguration containerConfiguration, |
||||
|
Action<AliyunBlobProviderConfiguration> aliyunConfigureAction) |
||||
|
{ |
||||
|
containerConfiguration.ProviderType = typeof(AliyunBlobProvider); |
||||
|
|
||||
|
aliyunConfigureAction(new AliyunBlobProviderConfiguration(containerConfiguration)); |
||||
|
|
||||
|
return containerConfiguration; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,148 @@ |
|||||
|
using Aliyun.OSS; |
||||
|
using LINGYUN.Abp.Aliyun.Authorization; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public class AliyunBlobProvider : BlobProviderBase, ITransientDependency |
||||
|
{ |
||||
|
protected AbpAliyunOptions Options { get; } |
||||
|
protected IAliyunBlobNameCalculator AliyunBlobNameCalculator { get; } |
||||
|
|
||||
|
public AliyunBlobProvider( |
||||
|
IOptions<AbpAliyunOptions> options, |
||||
|
IAliyunBlobNameCalculator aliyunBlobNameCalculator) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
AliyunBlobNameCalculator = aliyunBlobNameCalculator; |
||||
|
} |
||||
|
|
||||
|
public override async Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
||||
|
{ |
||||
|
var blobName = AliyunBlobNameCalculator.Calculate(args); |
||||
|
|
||||
|
if (await BlobExistsAsync(args, blobName)) |
||||
|
{ |
||||
|
var ossClient = GetOssClient(args); |
||||
|
|
||||
|
return ossClient.DeleteObject(GetBucketName(args), blobName).DeleteMarker; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public override async Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
||||
|
{ |
||||
|
var blobName = AliyunBlobNameCalculator.Calculate(args); |
||||
|
|
||||
|
return await BlobExistsAsync(args, blobName); |
||||
|
} |
||||
|
|
||||
|
public override async Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) |
||||
|
{ |
||||
|
var blobName = AliyunBlobNameCalculator.Calculate(args); |
||||
|
|
||||
|
if (!await BlobExistsAsync(args, blobName)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var ossClient = GetOssClient(args); |
||||
|
var ossObject = ossClient.GetObject(GetBucketName(args), blobName); |
||||
|
// 返回原始结果才会调用 Stream.ReadAsync();
|
||||
|
return ossObject.Content; |
||||
|
} |
||||
|
|
||||
|
public override async Task SaveAsync(BlobProviderSaveArgs args) |
||||
|
{ |
||||
|
var blobName = AliyunBlobNameCalculator.Calculate(args); |
||||
|
var configuration = args.Configuration.GetAliyunConfiguration(); |
||||
|
if (!args.OverrideExisting && await BlobExistsAsync(args, blobName)) |
||||
|
{ |
||||
|
throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the bucketName '{GetBucketName(args)}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); |
||||
|
} |
||||
|
|
||||
|
if (configuration.CreateBucketIfNotExists) |
||||
|
{ |
||||
|
await CreateBucketIfNotExists(args, configuration.CreateBucketReferer); |
||||
|
} |
||||
|
|
||||
|
var bucketName = GetBucketName(args); |
||||
|
var ossClient = GetOssClient(args); |
||||
|
|
||||
|
if (args.OverrideExisting && await BlobExistsAsync(args, blobName)) |
||||
|
{ |
||||
|
ossClient.DeleteObject(bucketName, blobName); |
||||
|
} |
||||
|
|
||||
|
ossClient.PutObject(bucketName, blobName, args.BlobStream); |
||||
|
} |
||||
|
|
||||
|
protected virtual OssClient GetOssClient(BlobProviderArgs args) |
||||
|
{ |
||||
|
var configuration = args.Configuration.GetAliyunConfiguration(); |
||||
|
var ossClient = new OssClient(configuration.Endpoint, Options.AccessKeyId, Options.AccessKeySecret); |
||||
|
return ossClient; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task CreateBucketIfNotExists(BlobProviderArgs args, IList<string> refererList = null) |
||||
|
{ |
||||
|
if (! await BucketExistsAsync(args)) |
||||
|
{ |
||||
|
var ossClient = GetOssClient(args); |
||||
|
var bucketName = GetBucketName(args); |
||||
|
|
||||
|
var request = new CreateBucketRequest(bucketName) |
||||
|
{ |
||||
|
//设置存储空间访问权限ACL。
|
||||
|
ACL = CannedAccessControlList.PublicReadWrite, |
||||
|
//设置数据容灾类型。
|
||||
|
DataRedundancyType = DataRedundancyType.ZRS |
||||
|
}; |
||||
|
|
||||
|
ossClient.CreateBucket(request); |
||||
|
|
||||
|
if (refererList != null && refererList.Count > 0) |
||||
|
{ |
||||
|
var srq = new SetBucketRefererRequest(bucketName, refererList); |
||||
|
ossClient.SetBucketReferer(srq); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private async Task<bool> BlobExistsAsync(BlobProviderArgs args, string blobName) |
||||
|
{ |
||||
|
var ossClient = GetOssClient(args); |
||||
|
var bucketExists = await BucketExistsAsync(args); |
||||
|
if (bucketExists) |
||||
|
{ |
||||
|
var objectExists = ossClient.DoesObjectExist(GetBucketName(args), blobName); |
||||
|
|
||||
|
return objectExists; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
private Task<bool> BucketExistsAsync(BlobProviderArgs args) |
||||
|
{ |
||||
|
var ossClient = GetOssClient(args); |
||||
|
var bucketExists = ossClient.DoesBucketExist(GetBucketName(args)); |
||||
|
|
||||
|
return Task.FromResult(bucketExists); |
||||
|
} |
||||
|
|
||||
|
private static string GetBucketName(BlobProviderArgs args) |
||||
|
{ |
||||
|
var configuration = args.Configuration.GetAliyunConfiguration(); |
||||
|
return configuration.BucketName.IsNullOrWhiteSpace() |
||||
|
? args.ContainerName |
||||
|
: configuration.BucketName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public class AliyunBlobProviderConfiguration |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 数据中心
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详见 https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.14.417cd47eLc9LHc#concept-zt4-cvy-5db
|
||||
|
/// </remarks>
|
||||
|
public string Endpoint |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.Endpoint); |
||||
|
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint, Check.NotNullOrWhiteSpace(value, nameof(value))); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 命名空间
|
||||
|
/// </summary>
|
||||
|
public string BucketName |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.BucketName); |
||||
|
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.BucketName, Check.NotNullOrWhiteSpace(value, nameof(value))); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 命名空间不存在是否创建
|
||||
|
/// </summary>
|
||||
|
public bool CreateBucketIfNotExists |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, false); |
||||
|
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, value); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 创建命名空间时防盗链列表
|
||||
|
/// </summary>
|
||||
|
public List<string> CreateBucketReferer |
||||
|
{ |
||||
|
get => _containerConfiguration.GetConfiguration<List<string>>(AliyunBlobProviderConfigurationNames.CreateBucketReferer); |
||||
|
set |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
_containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketReferer, new List<string>()); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketReferer, value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private readonly BlobContainerConfiguration _containerConfiguration; |
||||
|
|
||||
|
public AliyunBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) |
||||
|
{ |
||||
|
_containerConfiguration = containerConfiguration; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public static class AliyunBlobProviderConfigurationNames |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 数据中心
|
||||
|
/// </summary>
|
||||
|
public const string Endpoint = "Aliyun:OSS:Endpoint"; |
||||
|
/// <summary>
|
||||
|
/// 命名空间
|
||||
|
/// </summary>
|
||||
|
public const string BucketName = "Aliyun:OSS:BucketName"; |
||||
|
/// <summary>
|
||||
|
/// 命名空间不存在是否创建
|
||||
|
/// </summary>
|
||||
|
public const string CreateBucketIfNotExists = "Aliyun:OSS:CreateBucketIfNotExists"; |
||||
|
/// <summary>
|
||||
|
/// 创建命名空间时防盗链列表
|
||||
|
/// </summary>
|
||||
|
public const string CreateBucketReferer = "Aliyun:OSS:CreateBucketReferer"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using Volo.Abp.BlobStoring; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public class DefaultAliyunBlobNameCalculator : IAliyunBlobNameCalculator, ITransientDependency |
||||
|
{ |
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
|
||||
|
public DefaultAliyunBlobNameCalculator( |
||||
|
ICurrentTenant currentTenant) |
||||
|
{ |
||||
|
CurrentTenant = currentTenant; |
||||
|
} |
||||
|
|
||||
|
public string Calculate(BlobProviderArgs args) |
||||
|
{ |
||||
|
return CurrentTenant.Id == null |
||||
|
? $"host/{args.BlobName}" |
||||
|
: $"tenants/{CurrentTenant.Id.Value:D}/{args.BlobName}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.BlobStoring; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public interface IAliyunBlobNameCalculator |
||||
|
{ |
||||
|
string Calculate(BlobProviderArgs args); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\common\LINGYUN.Abp.BlobStoring.Aliyun\LINGYUN.Abp.BlobStoring.Aliyun.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using LINGYUN.Abp.Tests; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public class AbpBlobStoringAliyunTestBase : AbpTestsBase<AbpBlobStoringAliyunTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
using Aliyun.OSS; |
||||
|
using LINGYUN.Abp.Tests; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpBlobStoringModule), |
||||
|
typeof(AbpBlobStoringAliyunModule), |
||||
|
typeof(AbpTestsBaseModule), |
||||
|
typeof(AbpAutofacModule) |
||||
|
)] |
||||
|
public class AbpBlobStoringAliyunTestModule : AbpModule |
||||
|
{ |
||||
|
private string _bucketName; |
||||
|
private string _accessKeyId; |
||||
|
private string _accessKeySecret; |
||||
|
private string _endPoint; |
||||
|
|
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configurationOptions = new AbpConfigurationBuilderOptions |
||||
|
{ |
||||
|
BasePath = @"D:\Projects\Development\Abp\BlobStoring\Aliyun", |
||||
|
EnvironmentName = "Development" |
||||
|
}; |
||||
|
|
||||
|
context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(configurationOptions)); |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
|
||||
|
_endPoint = configuration[AliyunBlobProviderConfigurationNames.Endpoint]; |
||||
|
_bucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName]; |
||||
|
_accessKeyId = configuration["Aliyun:Auth:AccessKeyId"]; |
||||
|
_accessKeySecret = configuration["Aliyun:Auth:AccessKeySecret"]; |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationShutdown(ApplicationShutdownContext context) |
||||
|
{ |
||||
|
var ossClient = new OssClient(_endPoint, _accessKeyId, _accessKeySecret); |
||||
|
if (ossClient.DoesBucketExist(_bucketName)) |
||||
|
{ |
||||
|
ossClient.DeleteBucket(_bucketName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,99 @@ |
|||||
|
using LINGYUN.Abp.BlobStoring.TestObjects; |
||||
|
using Shouldly; |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.BlobStoring; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace LINGYUN.Abp.BlobStoring.Aliyun |
||||
|
{ |
||||
|
public class BlobContainer_Tests : AbpBlobStoringAliyunTestBase |
||||
|
{ |
||||
|
protected IBlobContainer<TestContainer1> Container { get; } |
||||
|
public BlobContainer_Tests() |
||||
|
{ |
||||
|
Container = GetRequiredService<IBlobContainer<TestContainer1>>(); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData("test-blob-1")] |
||||
|
[InlineData("test-blob-1.txt")] |
||||
|
[InlineData("test-folder/test-blob-1")] |
||||
|
public async Task Should_Save_And_Get_Blobs(string blobName) |
||||
|
{ |
||||
|
var testContent = "test content".GetBytes(); |
||||
|
await Container.SaveAsync(blobName, testContent); |
||||
|
try |
||||
|
{ |
||||
|
var resultBytes = await Container.GetAllBytesAsync(blobName); |
||||
|
resultBytes.SequenceEqual(testContent).ShouldBeTrue(); |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
await Container.DeleteAsync(blobName); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Overwrite_Pre_Saved_Blob_If_Requested() |
||||
|
{ |
||||
|
var blobName = "test-blob-1"; |
||||
|
|
||||
|
var testContent = "test content".GetBytes(); |
||||
|
await Container.SaveAsync(blobName, testContent); |
||||
|
|
||||
|
var testContentOverwritten = "test content overwritten".GetBytes(); |
||||
|
await Container.SaveAsync(blobName, testContentOverwritten, true); |
||||
|
|
||||
|
var result = await Container.GetAllBytesAsync(blobName); |
||||
|
result.SequenceEqual(testContentOverwritten).ShouldBeTrue(); |
||||
|
|
||||
|
await Container.DeleteAsync(blobName); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Not_Allow_To_Overwrite_Pre_Saved_Blob_By_Default() |
||||
|
{ |
||||
|
var blobName = "test-blob-1"; |
||||
|
|
||||
|
var testContent = "test content".GetBytes(); |
||||
|
await Container.SaveAsync(blobName, testContent); |
||||
|
|
||||
|
var testContentOverwritten = "test content overwritten".GetBytes(); |
||||
|
await Assert.ThrowsAsync<BlobAlreadyExistsException>(() => |
||||
|
Container.SaveAsync(blobName, testContentOverwritten) |
||||
|
); |
||||
|
|
||||
|
await Container.DeleteAsync(blobName); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData("test-blob-1")] |
||||
|
[InlineData("test-blob-1.txt")] |
||||
|
[InlineData("test-folder/test-blob-1")] |
||||
|
public async Task Should_Delete_Saved_Blobs(string blobName) |
||||
|
{ |
||||
|
await Container.SaveAsync(blobName, "test content".GetBytes()); |
||||
|
(await Container.GetAllBytesAsync(blobName)).ShouldNotBeNull(); |
||||
|
|
||||
|
await Container.DeleteAsync(blobName); |
||||
|
(await Container.GetAllBytesOrNullAsync(blobName)).ShouldBeNull(); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData("test-blob-1")] |
||||
|
[InlineData("test-blob-1.txt")] |
||||
|
[InlineData("test-folder/test-blob-1")] |
||||
|
public virtual async Task Saved_Blobs_Should_Exists(string blobName) |
||||
|
{ |
||||
|
await Container.SaveAsync(blobName, "test content".GetBytes()); |
||||
|
(await Container.ExistsAsync(blobName)).ShouldBeTrue(); |
||||
|
|
||||
|
await Container.DeleteAsync(blobName); |
||||
|
(await Container.ExistsAsync(blobName)).ShouldBeFalse(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace LINGYUN.Abp.BlobStoring.TestObjects |
||||
|
{ |
||||
|
public class TestContainer1 |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
||||
|
<PackageReference Include="NSubstitute" Version="4.2.1" /> |
||||
|
<PackageReference Include="Shouldly" Version="3.0.2" /> |
||||
|
<PackageReference Include="xunit" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> |
||||
|
<PackageReference Include="Volo.Abp.Autofac" Version="2.9.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Authorization" Version="2.9.0" /> |
||||
|
<PackageReference Include="Volo.Abp.TestBase" Version="2.9.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,59 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Testing; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Tests |
||||
|
{ |
||||
|
public abstract class AbpTestsBase<TStartupModule> : AbpIntegratedTest<TStartupModule> |
||||
|
where TStartupModule : IAbpModule |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
|
||||
|
protected virtual Task WithUnitOfWorkAsync(Func<Task> func) |
||||
|
{ |
||||
|
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func<Task> action) |
||||
|
{ |
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
||||
|
|
||||
|
using (var uow = uowManager.Begin(options)) |
||||
|
{ |
||||
|
await action(); |
||||
|
|
||||
|
await uow.CompleteAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func) |
||||
|
{ |
||||
|
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options, Func<Task<TResult>> func) |
||||
|
{ |
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
||||
|
|
||||
|
using (var uow = uowManager.Begin(options)) |
||||
|
{ |
||||
|
var result = await func(); |
||||
|
await uow.CompleteAsync(); |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Authorization; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Tests |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAutofacModule), |
||||
|
typeof(AbpTestBaseModule), |
||||
|
typeof(AbpAuthorizationModule) |
||||
|
)] |
||||
|
public class AbpTestsBaseModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAlwaysAllowAuthorization(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue