-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6708 from totpero/blob-storing
Blob storing feature
- Loading branch information
Showing
110 changed files
with
3,202 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<Import Project="..\..\common.props" /> | ||
<Import Project="..\..\configureawait.props" /> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard2.0</TargetFramework> | ||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
<AssemblyName>Abp.BlobStoring.Azure</AssemblyName> | ||
<PackageId>Abp.BlobStoring.Azure</PackageId> | ||
<PackageTags>asp.net;asp.net mvc;boilerplate;application framework;web framework;framework;domain driven design;blob storing; azure</PackageTags> | ||
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute> | ||
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute> | ||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> | ||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> | ||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> | ||
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute> | ||
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance> | ||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild> | ||
<RootNamespace>Abp</RootNamespace> | ||
<Description>Abp.BlobStoring.Azure</Description> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Abp.BlobStoring\Abp.BlobStoring.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Azure.Storage.Blobs" Version="12.19.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Update="Fody" Version="6.8.0"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.1.1" /> | ||
</ItemGroup> | ||
|
||
</Project> |
14 changes: 14 additions & 0 deletions
14
src/Abp.BlobStoring.Azure/BlobStoring/Azure/AbpBlobStoringAzureModule.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System.Reflection; | ||
using Abp.Modules; | ||
|
||
namespace Abp.BlobStoring.Azure | ||
{ | ||
[DependsOn(typeof(AbpBlobStoringModule))] | ||
public class AbpBlobStoringAzureModule : AbpModule | ||
{ | ||
public override void Initialize() | ||
{ | ||
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/Abp.BlobStoring.Azure/BlobStoring/Azure/AzureBlobContainerConfigurationExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
|
||
namespace Abp.BlobStoring.Azure | ||
{ | ||
public static class AzureBlobContainerConfigurationExtensions | ||
{ | ||
public static AzureBlobProviderConfiguration GetAzureConfiguration( | ||
this BlobContainerConfiguration containerConfiguration) | ||
{ | ||
return new AzureBlobProviderConfiguration(containerConfiguration); | ||
} | ||
|
||
public static BlobContainerConfiguration UseAzure( | ||
this BlobContainerConfiguration containerConfiguration, | ||
Action<AzureBlobProviderConfiguration> azureConfigureAction) | ||
{ | ||
containerConfiguration.ProviderType = typeof(AzureBlobProvider); | ||
containerConfiguration.NamingNormalizers.TryAdd<AzureBlobNamingNormalizer>(); | ||
|
||
azureConfigureAction(new AzureBlobProviderConfiguration(containerConfiguration)); | ||
|
||
return containerConfiguration; | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/Abp.BlobStoring.Azure/BlobStoring/Azure/AzureBlobNamingNormalizer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using System.Globalization; | ||
using System.Text.RegularExpressions; | ||
using Abp.Localization; | ||
using Abp.Dependency; | ||
|
||
namespace Abp.BlobStoring.Azure | ||
{ | ||
public class AzureBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency | ||
{ | ||
/// <summary> | ||
///https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names | ||
/// </summary> | ||
public virtual string NormalizeContainerName(string containerName) | ||
{ | ||
using (CultureInfoHelper.Use(CultureInfo.InvariantCulture)) | ||
{ | ||
// All letters in a container name must be lowercase. | ||
containerName = containerName.ToLower(); | ||
|
||
// Container names must be from 3 through 63 characters long. | ||
if (containerName.Length > 63) | ||
{ | ||
containerName = containerName.Substring(0, 63); | ||
} | ||
|
||
// 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"; | ||
} | ||
} | ||
|
||
return containerName; | ||
} | ||
} | ||
|
||
/// <summary> | ||
///https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#blob-names | ||
/// </summary> | ||
public virtual string NormalizeBlobName(string blobName) | ||
{ | ||
return blobName; | ||
} | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
src/Abp.BlobStoring.Azure/BlobStoring/Azure/AzureBlobProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
using Abp.Dependency; | ||
using Abp.Extensions; | ||
using Azure.Storage.Blobs; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
|
||
namespace Abp.BlobStoring.Azure | ||
{ | ||
public class AzureBlobProvider : BlobProviderBase, ITransientDependency | ||
{ | ||
protected IAzureBlobNameCalculator AzureBlobNameCalculator { get; } | ||
protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; } | ||
|
||
public AzureBlobProvider( | ||
IAzureBlobNameCalculator azureBlobNameCalculator, | ||
IBlobNormalizeNamingService blobNormalizeNamingService) | ||
{ | ||
AzureBlobNameCalculator = azureBlobNameCalculator; | ||
BlobNormalizeNamingService = blobNormalizeNamingService; | ||
} | ||
|
||
public override async Task SaveAsync(BlobProviderSaveArgs args) | ||
{ | ||
var blobName = AzureBlobNameCalculator.Calculate(args); | ||
var configuration = args.Configuration.GetAzureConfiguration(); | ||
|
||
if (!args.OverrideExisting && await BlobExistsAsync(args, blobName)) | ||
{ | ||
throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{GetContainerName(args)}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); | ||
} | ||
|
||
if (configuration.CreateContainerIfNotExists) | ||
{ | ||
await CreateContainerIfNotExists(args); | ||
} | ||
|
||
await GetBlobClient(args, blobName).UploadAsync(args.BlobStream, true); | ||
} | ||
|
||
public override async Task<bool> DeleteAsync(BlobProviderDeleteArgs args) | ||
{ | ||
var blobName = AzureBlobNameCalculator.Calculate(args); | ||
|
||
if (await BlobExistsAsync(args, blobName)) | ||
{ | ||
return await GetBlobClient(args, blobName).DeleteIfExistsAsync(); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public override async Task<bool> ExistsAsync(BlobProviderExistsArgs args) | ||
{ | ||
var blobName = AzureBlobNameCalculator.Calculate(args); | ||
|
||
return await BlobExistsAsync(args, blobName); | ||
} | ||
|
||
public override async Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) | ||
{ | ||
var blobName = AzureBlobNameCalculator.Calculate(args); | ||
|
||
if (!await BlobExistsAsync(args, blobName)) | ||
{ | ||
return null; | ||
} | ||
|
||
var blobClient = GetBlobClient(args, blobName); | ||
var download = await blobClient.DownloadAsync(); | ||
return await TryCopyToMemoryStreamAsync(download.Value.Content, args.CancellationToken); | ||
} | ||
|
||
protected virtual BlobClient GetBlobClient(BlobProviderArgs args, string blobName) | ||
{ | ||
var blobContainerClient = GetBlobContainerClient(args); | ||
return blobContainerClient.GetBlobClient(blobName); | ||
} | ||
|
||
protected virtual BlobContainerClient GetBlobContainerClient(BlobProviderArgs args) | ||
{ | ||
var configuration = args.Configuration.GetAzureConfiguration(); | ||
var blobServiceClient = new BlobServiceClient(configuration.ConnectionString); | ||
return blobServiceClient.GetBlobContainerClient(GetContainerName(args)); | ||
} | ||
|
||
protected virtual async Task CreateContainerIfNotExists(BlobProviderArgs args) | ||
{ | ||
var blobContainerClient = GetBlobContainerClient(args); | ||
await blobContainerClient.CreateIfNotExistsAsync(); | ||
} | ||
|
||
protected virtual async Task<bool> BlobExistsAsync(BlobProviderArgs args, string blobName) | ||
{ | ||
// Make sure Blob Container exists. | ||
return await ContainerExistsAsync(GetBlobContainerClient(args)) && | ||
(await GetBlobClient(args, blobName).ExistsAsync()).Value; | ||
} | ||
|
||
protected virtual string GetContainerName(BlobProviderArgs args) | ||
{ | ||
var configuration = args.Configuration.GetAzureConfiguration(); | ||
return configuration.ContainerName.IsNullOrWhiteSpace() | ||
? args.ContainerName | ||
: BlobNormalizeNamingService.NormalizeContainerName(args.Configuration, configuration.ContainerName); | ||
} | ||
|
||
protected virtual async Task<bool> ContainerExistsAsync(BlobContainerClient blobContainerClient) | ||
{ | ||
return (await blobContainerClient.ExistsAsync()).Value; | ||
} | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/Abp.BlobStoring.Azure/BlobStoring/Azure/AzureBlobProviderConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
namespace Abp.BlobStoring.Azure | ||
{ | ||
public class AzureBlobProviderConfiguration | ||
{ | ||
public string ConnectionString | ||
{ | ||
get => _containerConfiguration.GetConfiguration<string>(AzureBlobProviderConfigurationNames.ConnectionString); | ||
set => _containerConfiguration.SetConfiguration(AzureBlobProviderConfigurationNames.ConnectionString, Check.NotNullOrWhiteSpace(value, nameof(value))); | ||
} | ||
|
||
/// <summary> | ||
/// This name may only contain lowercase letters, numbers, and hyphens, and must begin with a letter or a number. | ||
/// Each hyphen must be preceded and followed by a non-hyphen character. | ||
/// The name must also be between 3 and 63 characters long. | ||
/// If this parameter is not specified, the ContainerName of the <see cref="BlobProviderArgs"/> will be used. | ||
/// </summary> | ||
public string ContainerName | ||
{ | ||
get => _containerConfiguration.GetConfigurationOrDefault<string>(AzureBlobProviderConfigurationNames.ContainerName); | ||
set => _containerConfiguration.SetConfiguration(AzureBlobProviderConfigurationNames.ContainerName, value); | ||
} | ||
|
||
/// <summary> | ||
/// Default value: false. | ||
/// </summary> | ||
public bool CreateContainerIfNotExists | ||
{ | ||
get => _containerConfiguration.GetConfigurationOrDefault(AzureBlobProviderConfigurationNames.CreateContainerIfNotExists, false); | ||
set => _containerConfiguration.SetConfiguration(AzureBlobProviderConfigurationNames.CreateContainerIfNotExists, value); | ||
} | ||
|
||
private readonly BlobContainerConfiguration _containerConfiguration; | ||
|
||
public AzureBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) | ||
{ | ||
_containerConfiguration = containerConfiguration; | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/Abp.BlobStoring.Azure/BlobStoring/Azure/AzureBlobProviderConfigurationNames.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Abp.BlobStoring.Azure | ||
{ | ||
public static class AzureBlobProviderConfigurationNames | ||
{ | ||
public const string ConnectionString = "Azure.ConnectionString"; | ||
public const string ContainerName = "Azure.ContainerName"; | ||
public const string CreateContainerIfNotExists = "Azure.CreateContainerIfNotExists"; | ||
} | ||
} |
Oops, something went wrong.