Browse Source

feat: add volo.abp.blobstoring.aliyun from dev

pull/4735/head
shaoxiaoxu 6 years ago
parent
commit
0fef923453
  1. 36
      framework/Volo.Abp.sln
  2. 3
      framework/src/Volo.Abp.BlobStoring.Aliyun/FodyWeavers.xml
  3. 30
      framework/src/Volo.Abp.BlobStoring.Aliyun/FodyWeavers.xsd
  4. 27
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo.Abp.BlobStoring.Aliyun.csproj
  5. 17
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs
  6. 25
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs
  7. 56
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobNamingNormalizer.cs
  8. 81
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs
  9. 96
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs
  10. 15
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs
  11. 22
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs
  12. 77
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/DefaultOssClientFactory.cs
  13. 7
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs
  14. 9
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/IOssClientFactory.cs
  15. 7
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Properties/serviceDependencies.json
  16. 7
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Properties/serviceDependencies.local.json
  17. 20
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo.Abp.BlobStoring.Aliyun.Tests.csproj
  18. 19
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs
  19. 65
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs
  20. 34
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AliyunBlobContainer_Tests.cs
  21. 55
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AliyunBlobNameCalculator_Tests.cs
  22. 57
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNamingNormalizerProvider_Tests.cs
  23. 7
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/MyTestContainer.cs
  24. 1
      nupkg/common.ps1

36
framework/Volo.Abp.sln

@ -289,27 +289,31 @@ 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.EntityFrameworkCore.Oracle", "src\Volo.Abp.EntityFrameworkCore.Oracle\Volo.Abp.EntityFrameworkCore.Oracle.csproj", "{1738845A-5348-4EB8-B736-CD1D22A808B4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.Oracle", "src\Volo.Abp.EntityFrameworkCore.Oracle\Volo.Abp.EntityFrameworkCore.Oracle.csproj", "{1738845A-5348-4EB8-B736-CD1D22A808B4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Caching.StackExchangeRedis", "src\Volo.Abp.Caching.StackExchangeRedis\Volo.Abp.Caching.StackExchangeRedis.csproj", "{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Caching.StackExchangeRedis", "src\Volo.Abp.Caching.StackExchangeRedis\Volo.Abp.Caching.StackExchangeRedis.csproj", "{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Caching.StackExchangeRedis.Tests", "test\Volo.Abp.Caching.StackExchangeRedis.Tests\Volo.Abp.Caching.StackExchangeRedis.Tests.csproj", "{60D0E384-965E-4F81-9D71-B28F419254FC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Caching.StackExchangeRedis.Tests", "test\Volo.Abp.Caching.StackExchangeRedis.Tests\Volo.Abp.Caching.StackExchangeRedis.Tests.csproj", "{60D0E384-965E-4F81-9D71-B28F419254FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Aliyun", "src\Volo.Abp.BlobStoring.Aliyun\Volo.Abp.BlobStoring.Aliyun.csproj", "{98AC8166-6F07-45D4-9695-961B78E00611}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlobStoring.Aliyun.Tests", "test\Volo.Abp.BlobStoring.Aliyun.Tests\Volo.Abp.BlobStoring.Aliyun.Tests.csproj", "{B823E35A-96C4-4E1A-83A7-6BC52407D83D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -925,6 +929,14 @@ Global
{60D0E384-965E-4F81-9D71-B28F419254FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60D0E384-965E-4F81-9D71-B28F419254FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60D0E384-965E-4F81-9D71-B28F419254FC}.Release|Any CPU.Build.0 = Release|Any CPU
{98AC8166-6F07-45D4-9695-961B78E00611}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{98AC8166-6F07-45D4-9695-961B78E00611}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98AC8166-6F07-45D4-9695-961B78E00611}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98AC8166-6F07-45D4-9695-961B78E00611}.Release|Any CPU.Build.0 = Release|Any CPU
{B823E35A-96C4-4E1A-83A7-6BC52407D83D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B823E35A-96C4-4E1A-83A7-6BC52407D83D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B823E35A-96C4-4E1A-83A7-6BC52407D83D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B823E35A-96C4-4E1A-83A7-6BC52407D83D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1082,6 +1094,8 @@ Global
{1738845A-5348-4EB8-B736-CD1D22A808B4} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{2B83DF1F-0FD2-4DEA-ABC5-E324B51401D4} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{60D0E384-965E-4F81-9D71-B28F419254FC} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{98AC8166-6F07-45D4-9695-961B78E00611} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{B823E35A-96C4-4E1A-83A7-6BC52407D83D} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

3
framework/src/Volo.Abp.BlobStoring.Aliyun/FodyWeavers.xml

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

30
framework/src/Volo.Abp.BlobStoring.Aliyun/FodyWeavers.xsd

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

27
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo.Abp.BlobStoring.Aliyun.csproj

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.BlobStoring.Aliyun</AssemblyName>
<PackageId>Volo.Abp.BlobStoring.Aliyun</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="aliyun-net-sdk-sts" Version="3.0.4" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.10.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
</ItemGroup>
</Project>

17
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs

@ -0,0 +1,17 @@
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
namespace Volo.Abp.BlobStoring.Aliyun
{
/// <summary>
/// https://help.aliyun.com/document_detail/31817.html
/// </summary>
[DependsOn(
typeof(AbpBlobStoringModule),
typeof(AbpCachingModule)
)]
public class AbpBlobStoringAliyunModule: AbpModule
{
}
}

25
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs

@ -0,0 +1,25 @@
using System;
namespace Volo.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);
containerConfiguration.NamingNormalizers.TryAdd<AliyunBlobNamingNormalizer>();
aliyunConfigureAction(new AliyunBlobProviderConfiguration(containerConfiguration));
return containerConfiguration;
}
}
}

56
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobNamingNormalizer.cs

@ -0,0 +1,56 @@
using System.Text.RegularExpressions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BlobStoring.Aliyun
{
public class AliyunBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency
{
/// <summary>
/// 只允许小写字母、数字、短横线(-),且不能以短横线开头或结尾
/// Container names can contain only letters, numbers, and the dash (-) character
/// can't start or end with the dash (-) character
/// 3~63 个字符
/// Container names must be from 3 through 63 characters long
/// </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);
}
// can't start or end with the dash (-) character
containerName = containerName.Trim('-');
return containerName;
}
public virtual string NormalizeBlobName(string blobName)
{
return blobName;
}
}
}

81
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs

@ -0,0 +1,81 @@
using Aliyun.OSS;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BlobStoring.Aliyun
{
public class AliyunBlobProvider : BlobProviderBase, ITransientDependency
{
protected IOssClientFactory OssClientFactory { get; }
protected IAliyunBlobNameCalculator AliyunBlobNameCalculator { get; }
public AliyunBlobProvider(
IOssClientFactory ossClientFactory,
IAliyunBlobNameCalculator aliyunBlobNameCalculator)
{
OssClientFactory = ossClientFactory;
AliyunBlobNameCalculator = aliyunBlobNameCalculator;
}
private IOss GetOssClient(BlobContainerConfiguration blobContainerConfiguration)
{
var aliyunConfig = blobContainerConfiguration.GetAliyunConfiguration();
return OssClientFactory.Create(aliyunConfig);
}
private IOss GetOssClient(AliyunBlobProviderConfiguration aliyunConfig)
{
return OssClientFactory.Create(aliyunConfig);
}
public override async Task SaveAsync(BlobProviderSaveArgs args)
{
var blobName = AliyunBlobNameCalculator.Calculate(args);
if (!args.OverrideExisting && await ExistsAsync(new BlobProviderExistsArgs(args.ContainerName, args.Configuration, args.BlobName)))
{
throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{args.ContainerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten.");
}
var aliyunConfig = args.Configuration.GetAliyunConfiguration();
var OssClient = GetOssClient(aliyunConfig);
if (aliyunConfig.CreateContainerIfNotExists)
{
if (!OssClient.DoesBucketExist(args.ContainerName))
{
OssClient.CreateBucket(args.ContainerName);
}
}
OssClient.PutObject(args.ContainerName, blobName, args.BlobStream);
}
public override Task<bool> DeleteAsync(BlobProviderDeleteArgs args)
{
var blobName = AliyunBlobNameCalculator.Calculate(args);
var OssClient = GetOssClient(args.Configuration);
var result = OssClient.DeleteObject(args.ContainerName, blobName);
//TODO: undifend delete flag
//https://help.aliyun.com/document_detail/91924.html
return Task.FromResult(true);
}
public override Task<bool> ExistsAsync(BlobProviderExistsArgs args)
{
var blobName = AliyunBlobNameCalculator.Calculate(args);
var OssClient = GetOssClient(args.Configuration);
return Task.FromResult(OssClient.DoesObjectExist(args.ContainerName, blobName));
}
public override async Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
{
var blobName = AliyunBlobNameCalculator.Calculate(args);
var OssClient = GetOssClient(args.Configuration);
if (!await ExistsAsync(new BlobProviderExistsArgs(args.ContainerName, args.Configuration, args.BlobName)))
{
return null;
}
var result = OssClient.GetObject(args.ContainerName, blobName);
return result.Content;
}
}
}

96
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs

@ -0,0 +1,96 @@
using System;
namespace Volo.Abp.BlobStoring.Aliyun
{
/// <summary>
/// STS临时授权访问OSS:https://help.aliyun.com/document_detail/100624.html
/// </summary>
public class AliyunBlobProviderConfiguration
{
public string AccessKeyId
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.AccessKeyId);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.AccessKeyId, Check.NotNullOrWhiteSpace(value, nameof(value)));
}
public string AccessKeySecret
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.AccessKeySecret);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.AccessKeySecret, Check.NotNullOrWhiteSpace(value, nameof(value)));
}
/// <summary>
/// https://help.aliyun.com/document_detail/31837.html
/// eg: https://oss-cn-beijing.aliyuncs.com
/// </summary>
public string Endpoint
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.Endpoint);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint, Check.NotNullOrWhiteSpace(value, nameof(value)));
}
/// <summary>
/// STS https://help.aliyun.com/document_detail/66053.html
/// eg:cn-beijing
/// </summary>
public string RegionId
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.RegionId);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.RegionId, value);
}
/// <summary>
/// eg:acs:ram::$accountID:role/$roleName
/// </summary>
public string RoleArn
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.RoleArn);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.RoleArn, value);
}
public string RoleSessionName
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.RoleSessionName);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.RoleSessionName, value);
}
public int DurationSeconds
{
get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.DurationSeconds, 0);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.DurationSeconds, value);
}
public string Policy
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.Policy);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.Policy, value);
}
/// <summary>
/// Default value: false.
/// </summary>
public bool CreateContainerIfNotExists
{
get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateContainerIfNotExists, false);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateContainerIfNotExists, value);
}
private readonly BlobContainerConfiguration _containerConfiguration;
public AliyunBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration)
{
_containerConfiguration = containerConfiguration;
}
public string ToOssKeyString()
{
Uri uPoint = new Uri(Endpoint);
return $"memorycache:aliyun:id:{AccessKeyId},sec:{AccessKeySecret},ept:{uPoint.Host.ToLower()}";
}
public string ToOssWithStsKeyString()
{
return ToOssKeyString() + $",rid:{RegionId},ra:{RoleArn},rsn:{RoleSessionName},pl:{Policy}";
}
}
}

15
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs

@ -0,0 +1,15 @@
namespace Volo.Abp.BlobStoring.Aliyun
{
public class AliyunBlobProviderConfigurationNames
{
public const string AccessKeyId = "Aliyun.AccessKeyId";
public const string AccessKeySecret = "Aliyun.AccessKeySecret";
public const string Endpoint = "Aliyun.Endpoint";
public const string RegionId = "Aliyun.RegionId";
public const string RoleArn = "Aliyun.RoleArn";
public const string RoleSessionName = "Aliyun.RoleSessionName";
public const string DurationSeconds = "Aliyun.DurationSeconds";
public const string Policy = "Aliyun.Policy";
public const string CreateContainerIfNotExists = "Aliyun.CreateContainerIfNotExists";
}
}

22
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs

@ -0,0 +1,22 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.BlobStoring.Aliyun
{
public class DefaultAliyunBlobNameCalculator: IAliyunBlobNameCalculator, ITransientDependency
{
protected ICurrentTenant CurrentTenant { get; }
public DefaultAliyunBlobNameCalculator(ICurrentTenant currentTenant)
{
CurrentTenant = currentTenant;
}
public virtual string Calculate(BlobProviderArgs args)
{
return CurrentTenant.Id == null
? $"host/{args.BlobName}"
: $"tenants/{CurrentTenant.Id.Value:D}/{args.BlobName}";
}
}
}

77
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/DefaultOssClientFactory.cs

@ -0,0 +1,77 @@
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Auth.Sts;
using Aliyun.Acs.Core.Http;
using Aliyun.Acs.Core.Profile;
using Aliyun.OSS;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BlobStoring.Aliyun
{
/// <summary>
/// STS:https://help.aliyun.com/document_detail/28756.html
/// STS or sub account number
/// </summary>
public class DefaultOssClientFactory : IOssClientFactory, ITransientDependency
{
private readonly IBlobContainerConfigurationProvider _configurationProvider;
private readonly IMemoryCache _cache;
public DefaultOssClientFactory(
IBlobContainerConfigurationProvider configurationProvider,
IMemoryCache cache)
{
_configurationProvider = configurationProvider;
_cache = cache;
}
public virtual IOss Create(AliyunBlobProviderConfiguration aliyunConfig)
{
//使用账号 sub account number
if (aliyunConfig.DurationSeconds <= 0)
{
var key = aliyunConfig.ToOssKeyString();
var iOssClient = _cache.Get<IOss>(key);
if (iOssClient != null)
{
return iOssClient;
}
iOssClient = new OssClient(aliyunConfig.Endpoint, aliyunConfig.AccessKeyId, aliyunConfig.AccessKeySecret);
_cache.Set(key, iOssClient);
return iOssClient;
}
else
{
//使用STS
var key = aliyunConfig.ToOssWithStsKeyString();
var iOssClient = _cache.Get<IOss>(key);
if (iOssClient != null)
{
return iOssClient;
}
IClientProfile profile = DefaultProfile.GetProfile(
aliyunConfig.RegionId,
aliyunConfig.AccessKeyId,
aliyunConfig.AccessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
//构建AssumeRole请求
AssumeRoleRequest request = new AssumeRoleRequest
{
AcceptFormat = FormatType.JSON,
//指定角色ARN
RoleArn = aliyunConfig.RoleArn,
RoleSessionName = aliyunConfig.RoleSessionName,
//设置Token有效期,可选参数,默认3600秒
DurationSeconds = aliyunConfig.DurationSeconds,
//设置Token的附加权限策略;在获取Token时,通过额外设置一个权限策略进一步减小Token的权限
Policy = aliyunConfig.Policy.IsNullOrEmpty() ? null : aliyunConfig.Policy,
};
var response = client.GetAcsResponse(request);
iOssClient = new OssClient(aliyunConfig.Endpoint, response.Credentials.AccessKeyId, response.Credentials.AccessKeySecret, response.Credentials.SecurityToken);
_cache.Set(key, iOssClient, TimeSpan.FromSeconds(aliyunConfig.DurationSeconds));
return iOssClient;
}
}
}
}

7
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.BlobStoring.Aliyun
{
public interface IAliyunBlobNameCalculator
{
string Calculate(BlobProviderArgs args);
}
}

9
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/IOssClientFactory.cs

@ -0,0 +1,9 @@
using Aliyun.OSS;
namespace Volo.Abp.BlobStoring.Aliyun
{
public interface IOssClientFactory
{
IOss Create(AliyunBlobProviderConfiguration args);
}
}

7
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Properties/serviceDependencies.json

@ -0,0 +1,7 @@
{
"dependencies": {
"secrets1": {
"type": "secrets"
}
}
}

7
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Properties/serviceDependencies.local.json

@ -0,0 +1,7 @@
{
"dependencies": {
"secrets1": {
"type": "secrets.user"
}
}
}

20
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo.Abp.BlobStoring.Aliyun.Tests.csproj

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace />
<UserSecretsId>fe9a87da-3584-40e0-a06c-aa499936015d</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.BlobStoring.Aliyun\Volo.Abp.BlobStoring.Aliyun.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="3.1.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<ProjectReference Include="..\Volo.Abp.BlobStoring.Tests\Volo.Abp.BlobStoring.Tests.csproj" />
</ItemGroup>
</Project>

19
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs

@ -0,0 +1,19 @@
using Volo.Abp.Testing;
namespace Volo.Abp.BlobStoring.Aliyun
{
public class AbpBlobStoringAliyunTestCommonBase : AbpIntegratedTest<AbpBlobStoringAliyunTestCommonModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}
public class AbpBlobStoringAliyunTestBase : AbpIntegratedTest<AbpBlobStoringAliyunTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}
}

65
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs

@ -0,0 +1,65 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.Modularity;
namespace Volo.Abp.BlobStoring.Aliyun
{
/// <summary>
/// This module will not try to connect to azure.
/// </summary>
[DependsOn(
typeof(AbpBlobStoringAliyunModule),
typeof(AbpBlobStoringTestModule)
)]
public class AbpBlobStoringAliyunTestCommonModule : AbpModule
{
}
[DependsOn(
typeof(AbpBlobStoringAliyunTestCommonModule)
)]
public class AbpBlobStoringAliyunTestModule : AbpModule
{
private const string UserSecretsId = "fe9a87da-3584-40e0-a06c-aa499936015d";
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(builderAction: builder =>
{
builder.AddUserSecrets(UserSecretsId);
}));
var configuration = context.Services.GetConfiguration();
var _accessKeyId = configuration["Aliyun:AccessKeyId"];
var _accessKeySecret = configuration["Aliyun:AccessKeySecret"];
var _endpoint = configuration["Aliyun:Endpoint"];
var _regionId = configuration["Aliyun:RegionId"];
var _roleArn = configuration["Aliyun:RoleArn"];
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureAll((containerName, containerConfiguration) =>
{
containerConfiguration.UseAliyun(aliyun =>
{
aliyun.AccessKeyId = _accessKeyId;
aliyun.AccessKeySecret = _accessKeySecret;
aliyun.Endpoint = _endpoint;//eg:https://oss-cn-beijing.aliyuncs.com
//STS
aliyun.RegionId = _regionId;//eg:cn-beijing
aliyun.RoleArn = _roleArn;//eg:acs:ram::1320235309887297:role/role-oss-xxxxx
aliyun.RoleSessionName = Guid.NewGuid().ToString("N");
aliyun.DurationSeconds = 3600;
aliyun.Policy = String.Empty;
//Other
aliyun.CreateContainerIfNotExists = true;
});
});
});
}
}
}

34
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AliyunBlobContainer_Tests.cs

@ -0,0 +1,34 @@
using Shouldly;
using System.IO;
using System.Text;
using Xunit;
namespace Volo.Abp.BlobStoring.Aliyun
{
public class AliyunBlobContainer_Tests : BlobContainer_Tests<AbpBlobStoringAliyunTestModule>
{
private readonly IBlobContainer<MyTestContainer> _blobContainer;
private readonly string _blobname = "my-blob";
private readonly string _stringContent = "my-blob-content";
public AliyunBlobContainer_Tests()
{
_blobContainer = GetRequiredService<IBlobContainer<MyTestContainer>>();
}
[Fact]
public async void BlobContainer_Test()
{
var streamContent = Encoding.Default.GetBytes(_stringContent);
await _blobContainer.SaveAsync(_blobname, streamContent, true);
var streamData = await _blobContainer.GetAsync(_blobname);
var tfExist = await _blobContainer.ExistsAsync(_blobname);
if (tfExist)
{
await _blobContainer.DeleteAsync(_blobname);
}
StreamReader reader = new StreamReader(streamData);
var stringData = reader.ReadToEnd();// Encoding.Default.GetString(bytes);
stringData.ShouldBe(_stringContent);
}
}
}

55
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AliyunBlobNameCalculator_Tests.cs

@ -0,0 +1,55 @@
using Shouldly;
using System;
using Volo.Abp.MultiTenancy;
using Xunit;
namespace Volo.Abp.BlobStoring.Aliyun
{
public class AliyunBlobNameCalculator_Tests: AbpBlobStoringAliyunTestCommonBase
{
private readonly IAliyunBlobNameCalculator _calculator;
private readonly ICurrentTenant _currentTenant;
private const string AliyunSeparator = "/";
public AliyunBlobNameCalculator_Tests()
{
_calculator = GetRequiredService<IAliyunBlobNameCalculator>();
_currentTenant = GetRequiredService<ICurrentTenant>();
}
[Fact]
public void Default_Settings()
{
_calculator.Calculate(
GetArgs("my-container", "my-blob")
).ShouldBe($"host{AliyunSeparator}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{AliyunSeparator}{tenantId:D}{AliyunSeparator}my-blob");
}
}
private static BlobProviderArgs GetArgs(
string containerName,
string blobName)
{
return new BlobProviderGetArgs(
containerName,
new BlobContainerConfiguration().UseAliyun(x =>
{
}),
blobName
);
}
}
}

57
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNamingNormalizerProvider_Tests.cs

@ -0,0 +1,57 @@
using Shouldly;
using Xunit;
namespace Volo.Abp.BlobStoring.Aliyun
{
public class DefaultAliyunBlobNamingNormalizerProvider_Tests: AbpBlobStoringAliyunTestCommonBase
{
private readonly IBlobNamingNormalizer _blobNamingNormalizer;
public DefaultAliyunBlobNamingNormalizerProvider_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);
}
}
}

7
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/MyTestContainer.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.BlobStoring.Aliyun
{
[BlobContainerName("my-container")]
public class MyTestContainer
{
}
}

1
nupkg/common.ps1

@ -58,6 +58,7 @@ $projects = (
"framework/src/Volo.Abp.BackgroundWorkers.Quartz",
"framework/src/Volo.Abp.BlobStoring",
"framework/src/Volo.Abp.BlobStoring.FileSystem",
"framework/src/Volo.Abp.BlobStoring.Aliyun",
"framework/src/Volo.Abp.BlobStoring.Azure",
"framework/src/Volo.Abp.Caching",
"framework/src/Volo.Abp.Caching.StackExchangeRedis",

Loading…
Cancel
Save