mirror of https://github.com/abpframework/abp.git
22 changed files with 476 additions and 190 deletions
@ -0,0 +1,24 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public static class FileSystemBlobContainerConfigurationExtensions |
|||
{ |
|||
public static FileSystemBlobProviderConfiguration GetFileSystemConfiguration( |
|||
this BlobContainerConfiguration containerConfiguration) |
|||
{ |
|||
return new FileSystemBlobProviderConfiguration(containerConfiguration); |
|||
} |
|||
|
|||
public static BlobContainerConfiguration UseFileSystem( |
|||
this BlobContainerConfiguration containerConfiguration, |
|||
Action<FileSystemBlobProviderConfiguration> fileSystemConfigureAction) |
|||
{ |
|||
containerConfiguration.ProviderType = typeof(FileSystemBlobProvider); |
|||
|
|||
fileSystemConfigureAction(new FileSystemBlobProviderConfiguration(containerConfiguration)); |
|||
|
|||
return containerConfiguration; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.IO; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
//TODO: What if the file is being used on create, delete or read?
|
|||
|
|||
public class FileSystemBlobProvider : BlobProviderBase |
|||
{ |
|||
public override async Task SaveAsync(BlobProviderSaveArgs args) |
|||
{ |
|||
var filePath = CalculateBlobFilePath(args); |
|||
|
|||
DirectoryHelper.CreateIfNotExists(Path.GetDirectoryName(filePath)); |
|||
|
|||
var fileMode = args.OverrideExisting |
|||
? FileMode.Create |
|||
: FileMode.CreateNew; |
|||
|
|||
using (var fileStream = File.Open(filePath, fileMode, FileAccess.Write)) |
|||
{ |
|||
//TODO: Truely implement this (like this? http://writeasync.net/?p=2621 or https://www.infoworld.com/article/2995387/how-to-perform-asynchronous-file-operations-in-c.html)
|
|||
|
|||
await args.BlobStream.CopyToAsync( |
|||
fileStream, |
|||
81920, //this is already the default value, but needed to set to be able to pass the cancellationToken
|
|||
args.CancellationToken |
|||
); |
|||
|
|||
await fileStream.FlushAsync(); |
|||
} |
|||
} |
|||
|
|||
public override Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
|||
{ |
|||
var filePath = CalculateBlobFilePath(args); |
|||
|
|||
return Task.FromResult(FileHelper.DeleteIfExists(filePath)); |
|||
} |
|||
|
|||
public override Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
|||
{ |
|||
var filePath = CalculateBlobFilePath(args); |
|||
|
|||
return Task.FromResult(File.Exists(filePath)); |
|||
} |
|||
|
|||
public override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) |
|||
{ |
|||
var filePath = CalculateBlobFilePath(args); |
|||
|
|||
if (!File.Exists(filePath)) |
|||
{ |
|||
return Task.FromResult<Stream>(null); |
|||
} |
|||
|
|||
return Task.FromResult<Stream>(File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)); |
|||
} |
|||
|
|||
protected virtual string CalculateBlobFilePath(BlobProviderArgs args) |
|||
{ |
|||
var blobPath = args.Configuration.GetFileSystemConfiguration().BasePath; |
|||
|
|||
if (args.TenantId == null) |
|||
{ |
|||
blobPath = Path.Combine(blobPath, "host"); |
|||
} |
|||
else |
|||
{ |
|||
blobPath = Path.Combine(blobPath, "tenants", args.TenantId.Value.ToString("D")); |
|||
} |
|||
|
|||
blobPath = Path.Combine(blobPath, args.ContainerName, args.BlobName); |
|||
|
|||
return blobPath; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public class FileSystemBlobProviderConfiguration |
|||
{ |
|||
|
|||
public string BasePath |
|||
{ |
|||
get => _containerConfiguration.GetConfiguration<string>(FileSystemBlobProviderConfigurationNames.BasePath); |
|||
set => _containerConfiguration.SetConfiguration(FileSystemBlobProviderConfigurationNames.BasePath, Check.NotNullOrWhiteSpace(value, nameof(value))); |
|||
} |
|||
|
|||
private readonly BlobContainerConfiguration _containerConfiguration; |
|||
|
|||
public FileSystemBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) |
|||
{ |
|||
_containerConfiguration = containerConfiguration; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public static class FileSystemBlobProviderConfigurationNames |
|||
{ |
|||
public const string BasePath = "BasePath"; |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,190 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobContainer<TContainer> : IBlobContainer<TContainer> |
|||
where TContainer : class |
|||
{ |
|||
private readonly IBlobContainer _container; |
|||
|
|||
public BlobContainer(IBlobContainerFactory blobContainerFactory) |
|||
{ |
|||
_container = blobContainerFactory.Create<TContainer>(); |
|||
} |
|||
|
|||
public Task SaveAsync( |
|||
string name, |
|||
Stream stream, |
|||
bool overrideExisting = false, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.SaveAsync( |
|||
name, |
|||
stream, |
|||
overrideExisting, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<bool> DeleteAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.DeleteAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<bool> ExistsAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.ExistsAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<Stream> GetAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.GetAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
|
|||
public Task<Stream> GetOrNullAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.GetOrNullAsync( |
|||
name, |
|||
cancellationToken |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class BlobContainer : IBlobContainer |
|||
{ |
|||
protected string ContainerName { get; } |
|||
|
|||
protected BlobContainerConfiguration Configuration { get; } |
|||
|
|||
protected IBlobProvider Provider { get; } |
|||
|
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
|
|||
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
|||
|
|||
public BlobContainer( |
|||
string containerName, |
|||
BlobContainerConfiguration configuration, |
|||
IBlobProvider provider, |
|||
ICurrentTenant currentTenant, |
|||
ICancellationTokenProvider cancellationTokenProvider) |
|||
{ |
|||
ContainerName = containerName; |
|||
Configuration = configuration; |
|||
Provider = provider; |
|||
CurrentTenant = currentTenant; |
|||
CancellationTokenProvider = cancellationTokenProvider; |
|||
} |
|||
|
|||
public virtual Task SaveAsync( |
|||
string name, |
|||
Stream stream, |
|||
bool overrideExisting = false, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.SaveAsync( |
|||
new BlobProviderSaveArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
stream, |
|||
overrideExisting, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<bool> DeleteAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.DeleteAsync( |
|||
new BlobProviderDeleteArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<bool> ExistsAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.ExistsAsync( |
|||
new BlobProviderExistsArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<Stream> GetAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.GetAsync( |
|||
new BlobProviderGetArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<Stream> GetOrNullAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.GetOrNullAsync( |
|||
new BlobProviderGetArgs( |
|||
ContainerName, |
|||
Configuration, |
|||
name, |
|||
GetTenantIdOrNull(), |
|||
CancellationTokenProvider.FallbackToProvider(cancellationToken) |
|||
) |
|||
); |
|||
} |
|||
|
|||
protected virtual Guid? GetTenantIdOrNull() |
|||
{ |
|||
if (!Configuration.IsMultiTenant) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return CurrentTenant.Id; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public static class BlobContainerConfigurationExtensions |
|||
{ |
|||
public static T GetConfiguration<T>( |
|||
[NotNull] this BlobContainerConfiguration containerConfiguration, |
|||
[NotNull] string name) |
|||
{ |
|||
return (T) containerConfiguration.GetConfiguration(name); |
|||
} |
|||
|
|||
public static object GetConfiguration( |
|||
[NotNull] this BlobContainerConfiguration containerConfiguration, |
|||
[NotNull] string name) |
|||
{ |
|||
var value = containerConfiguration.GetConfigurationOrNull(name); |
|||
if (value == null) |
|||
{ |
|||
throw new AbpException($"Could not find the configuration value for '{name}'!"); |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
} |
|||
} |
|||
@ -1,99 +0,0 @@ |
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobContainerToProviderAdapter : IBlobContainer |
|||
{ |
|||
protected string ContainerName { get; } |
|||
|
|||
protected BlobContainerConfiguration ContainerConfiguration { get; } |
|||
|
|||
protected IBlobProvider Provider { get; } |
|||
|
|||
public BlobContainerToProviderAdapter( |
|||
string containerName, |
|||
BlobContainerConfiguration containerConfiguration, |
|||
IBlobProvider provider) |
|||
{ |
|||
ContainerName = containerName; |
|||
ContainerConfiguration = containerConfiguration; |
|||
Provider = provider; |
|||
} |
|||
|
|||
public virtual Task SaveAsync( |
|||
string name, |
|||
Stream stream, |
|||
bool overrideExisting = false, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.SaveAsync( |
|||
new BlobProviderSaveArgs( |
|||
ContainerName, |
|||
ContainerConfiguration, |
|||
name, |
|||
stream, |
|||
overrideExisting, |
|||
cancellationToken |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<bool> DeleteAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.DeleteAsync( |
|||
new BlobProviderDeleteArgs( |
|||
ContainerName, |
|||
ContainerConfiguration, |
|||
name, |
|||
cancellationToken |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<bool> ExistsAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.ExistsAsync( |
|||
new BlobProviderExistsArgs( |
|||
ContainerName, |
|||
ContainerConfiguration, |
|||
name, |
|||
cancellationToken |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<Stream> GetAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.GetAsync( |
|||
new BlobProviderGetArgs( |
|||
ContainerName, |
|||
ContainerConfiguration, |
|||
name, |
|||
cancellationToken |
|||
) |
|||
); |
|||
} |
|||
|
|||
public virtual Task<Stream> GetOrNullAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return Provider.GetOrNullAsync( |
|||
new BlobProviderGetArgs( |
|||
ContainerName, |
|||
ContainerConfiguration, |
|||
name, |
|||
cancellationToken |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public abstract class BlobProviderBase : IBlobProvider |
|||
{ |
|||
public abstract Task SaveAsync(BlobProviderSaveArgs args); |
|||
|
|||
public abstract Task<bool> DeleteAsync(BlobProviderDeleteArgs args); |
|||
|
|||
public abstract Task<bool> ExistsAsync(BlobProviderExistsArgs args); |
|||
|
|||
public virtual async Task<Stream> GetAsync(BlobProviderGetArgs args) |
|||
{ |
|||
var result = await GetOrNullAsync(args); |
|||
if (result == null) |
|||
{ |
|||
//TODO: Consider to throw some type of "not found" exception and handle on the HTTP status side
|
|||
throw new AbpException($"Could not found the requested BLOB '{args.BlobName}' in the container '{args.ContainerName}'!"); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
public abstract Task<Stream> GetOrNullAsync(BlobProviderGetArgs args); |
|||
} |
|||
} |
|||
@ -1,41 +1,34 @@ |
|||
using System.IO; |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class BlobProviderSaveArgs |
|||
public class BlobProviderSaveArgs : BlobProviderArgs |
|||
{ |
|||
[NotNull] |
|||
public string ContainerName { get; } |
|||
|
|||
[NotNull] |
|||
public BlobContainerConfiguration Configuration { get; } |
|||
|
|||
[NotNull] |
|||
public string BlobName { get; } |
|||
|
|||
[NotNull] |
|||
public Stream BlobStream { get; } |
|||
|
|||
public bool OverrideExisting { get; } |
|||
|
|||
public CancellationToken CancellationToken { get; } |
|||
|
|||
public BlobProviderSaveArgs( |
|||
[NotNull] string containerName, |
|||
[NotNull] BlobContainerConfiguration configuration, |
|||
[NotNull] string blobName, |
|||
[NotNull] Stream blobStream, |
|||
bool overrideExisting = false, |
|||
[CanBeNull] Guid? tenantId = null, |
|||
CancellationToken cancellationToken = default) |
|||
: base( |
|||
containerName, |
|||
configuration, |
|||
blobName, |
|||
tenantId, |
|||
cancellationToken) |
|||
{ |
|||
ContainerName = Check.NotNullOrWhiteSpace(containerName, nameof(containerName)); |
|||
Configuration = Check.NotNull(configuration, nameof(configuration)); |
|||
BlobName = Check.NotNullOrWhiteSpace(blobName, nameof(blobName)); |
|||
BlobStream = Check.NotNull(blobStream, nameof(blobStream)); |
|||
OverrideExisting = overrideExisting; |
|||
CancellationToken = cancellationToken; |
|||
} |
|||
} |
|||
} |
|||
@ -1,42 +0,0 @@ |
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public class TypedBlobContainerWrapper<TContainer> : IBlobContainer<TContainer> |
|||
where TContainer: class |
|||
{ |
|||
private readonly IBlobContainer _container; |
|||
|
|||
public TypedBlobContainerWrapper(IBlobContainerFactory blobContainerFactory) |
|||
{ |
|||
_container = blobContainerFactory.Create<TContainer>(); |
|||
} |
|||
|
|||
public Task SaveAsync(string name, Stream stream, bool overrideExisting = false, CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.SaveAsync(name, stream, overrideExisting, cancellationToken); |
|||
} |
|||
|
|||
public Task<bool> DeleteAsync(string name, CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.DeleteAsync(name, cancellationToken); |
|||
} |
|||
|
|||
public Task<bool> ExistsAsync(string name, CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.ExistsAsync(name, cancellationToken); |
|||
} |
|||
|
|||
public Task<Stream> GetAsync(string name, CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.GetAsync(name, cancellationToken); |
|||
} |
|||
|
|||
public Task<Stream> GetOrNullAsync(string name, CancellationToken cancellationToken = default) |
|||
{ |
|||
return _container.GetOrNullAsync(name, cancellationToken); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue