Implemented basic BlobContainerFactory.

pull/4105/head
Halil İbrahim Kalkan 6 years ago
parent 1f41cd5671
commit f5caaaaa85

@ -1,9 +1,19 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Volo.Abp.BlobStoring
{
public class BlobContainerConfiguration : Dictionary<string, object>
{
[NotNull]
public string Name { get; }
public Type ProviderType { get; set; }
public BlobContainerConfiguration([NotNull] string name)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
}
}
}

@ -1,11 +1,21 @@
using System;
using System.Collections.Generic;
using System.IO;
using JetBrains.Annotations;
namespace Volo.Abp.BlobStoring
{
public class BlobContainerConfigurationDictionary : Dictionary<string, BlobContainerConfiguration>
{
public BlobContainerConfigurationDictionary Configure<TContainer>(Action<BlobContainerConfiguration> configureAction)
public BlobContainerConfiguration Default { get; }
public BlobContainerConfigurationDictionary()
{
Default = new BlobContainerConfiguration("_default");
}
public BlobContainerConfigurationDictionary Configure<TContainer>(
Action<BlobContainerConfiguration> configureAction)
{
return Configure(
BlobContainerNameAttribute.GetContainerName<TContainer>(),
@ -13,10 +23,28 @@ namespace Volo.Abp.BlobStoring
);
}
public BlobContainerConfigurationDictionary Configure(string name, Action<BlobContainerConfiguration> configureAction)
public BlobContainerConfigurationDictionary Configure(
[NotNull] string name,
[NotNull] Action<BlobContainerConfiguration> configureAction)
{
configureAction(this.GetOrAdd(name, () => new BlobContainerConfiguration()));
Check.NotNullOrWhiteSpace(name, nameof(name));
Check.NotNull(configureAction, nameof(configureAction));
configureAction(this.GetOrAdd(name, () => new BlobContainerConfiguration(name)));
return this;
}
public BlobContainerConfigurationDictionary ConfigureDefault(Action<BlobContainerConfiguration> configureAction)
{
configureAction(Default);
return this;
}
public BlobContainerConfiguration GetOrDefaultConfiguration(string name)
{
return AbpDictionaryExtensions.GetOrDefault(this, name) ??
Default;
}
}
}

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using Volo.Abp.BlobStoring.Providers;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.BlobStoring
{
public class BlobContainerFactory : IBlobContainerFactory, ITransientDependency
{
public IEnumerable<IBlobProvider> BlobProviders { get; }
protected AbpBlobStoringOptions Options { get; }
public BlobContainerFactory(
IOptions<AbpBlobStoringOptions> options,
IEnumerable<IBlobProvider> blobProviders)
{
BlobProviders = blobProviders;
Options = options.Value;
}
public virtual IBlobContainer Create(string name, CancellationToken cancellationToken = default)
{
var configuration = Options.Containers.GetOrDefaultConfiguration(name);
return new BlobContainerToProviderAdapter(
name,
configuration,
GetProvider(configuration)
);
}
[NotNull]
protected virtual IBlobProvider GetProvider(BlobContainerConfiguration configuration)
{
if (!BlobProviders.Any())
{
throw new AbpException("No BLOB Storage provider was registered! At least one provider must be registered to be able to use the Blog Storing System.");
}
foreach (var provider in BlobProviders)
{
if (ProxyHelper.GetUnProxiedType(provider).IsAssignableTo(configuration.ProviderType))
{
return provider;
}
}
throw new AbpException(
$"Could not find the BLOB Storage provider with the type ({configuration.ProviderType.AssemblyQualifiedName}) configured for the container {configuration.Name}"
);
}
}
}

@ -0,0 +1,99 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.BlobStoring.Providers
{
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,31 @@
using System.Threading;
using JetBrains.Annotations;
namespace Volo.Abp.BlobStoring.Providers
{
public abstract class BlobProviderArgs
{
[NotNull]
public string ContainerName { get; }
[NotNull]
public BlobContainerConfiguration Configuration { get; }
[NotNull]
public string BlobName { get; }
public CancellationToken CancellationToken { get; }
protected BlobProviderArgs(
[NotNull] string containerName,
[NotNull] BlobContainerConfiguration configuration,
[NotNull] string blobName,
CancellationToken cancellationToken = default)
{
ContainerName = Check.NotNullOrWhiteSpace(containerName, nameof(containerName));
Configuration = Check.NotNull(configuration, nameof(configuration));
BlobName = Check.NotNullOrWhiteSpace(blobName, nameof(blobName));
CancellationToken = cancellationToken;
}
}
}

@ -0,0 +1,21 @@
using System.Threading;
using JetBrains.Annotations;
namespace Volo.Abp.BlobStoring.Providers
{
public class BlobProviderDeleteArgs : BlobProviderArgs
{
public BlobProviderDeleteArgs(
[NotNull] string containerName,
[NotNull] BlobContainerConfiguration configuration,
[NotNull] string blobName,
CancellationToken cancellationToken = default)
: base(
containerName,
configuration,
blobName,
cancellationToken)
{
}
}
}

@ -0,0 +1,21 @@
using System.Threading;
using JetBrains.Annotations;
namespace Volo.Abp.BlobStoring.Providers
{
public class BlobProviderExistsArgs : BlobProviderArgs
{
public BlobProviderExistsArgs(
[NotNull] string containerName,
[NotNull] BlobContainerConfiguration configuration,
[NotNull] string blobName,
CancellationToken cancellationToken = default)
: base(
containerName,
configuration,
blobName,
cancellationToken)
{
}
}
}

@ -0,0 +1,21 @@
using System.Threading;
using JetBrains.Annotations;
namespace Volo.Abp.BlobStoring.Providers
{
public class BlobProviderGetArgs : BlobProviderArgs
{
public BlobProviderGetArgs(
[NotNull] string containerName,
[NotNull] BlobContainerConfiguration configuration,
[NotNull] string blobName,
CancellationToken cancellationToken = default)
: base(
containerName,
configuration,
blobName,
cancellationToken)
{
}
}
}

@ -0,0 +1,41 @@
using System.IO;
using System.Threading;
using JetBrains.Annotations;
namespace Volo.Abp.BlobStoring.Providers
{
public class BlobProviderSaveArgs
{
[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,
CancellationToken cancellationToken = default)
{
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;
}
}
}

@ -0,0 +1,18 @@
using System.IO;
using System.Threading.Tasks;
namespace Volo.Abp.BlobStoring.Providers
{
public interface IBlobProvider
{
Task SaveAsync(BlobProviderSaveArgs args);
Task<bool> DeleteAsync(BlobProviderDeleteArgs args);
Task<bool> ExistsAsync(BlobProviderExistsArgs args);
Task<Stream> GetAsync(BlobProviderGetArgs args);
Task<Stream> GetOrNullAsync(BlobProviderGetArgs args);
}
}

@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Reflection;
namespace Volo.Abp.DynamicProxy
@ -6,6 +7,7 @@ namespace Volo.Abp.DynamicProxy
public static class ProxyHelper
{
private const string ProxyNamespace = "Castle.Proxies";
/// <summary>
/// Returns dynamic proxy target object if this is a proxied object, otherwise returns the given object.
/// It supports Castle Dynamic Proxies.
@ -28,5 +30,10 @@ namespace Volo.Abp.DynamicProxy
return targetField.GetValue(obj);
}
public static Type GetUnProxiedType(object obj)
{
return UnProxy(obj).GetType();
}
}
}

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />

@ -1,6 +1,7 @@
using System.Collections.Generic;
using Microsoft.Extensions.Options;
using Shouldly;
using Volo.Abp.BlobStoring.TestObjects;
using Xunit;
namespace Volo.Abp.BlobStoring
@ -18,11 +19,11 @@ namespace Volo.Abp.BlobStoring
public void Should_Property_Set_And_Get_Options_For_Different_Containers()
{
var testContainer1Config = _options.Containers
.GetOrDefault(BlobContainerNameAttribute.GetContainerName<TestContainer1>());
.GetOrDefaultConfiguration(BlobContainerNameAttribute.GetContainerName<TestContainer1>());
testContainer1Config.ShouldContainKeyAndValue("TestConfig1", "TestValue1");
var testContainer2Config = _options.Containers
.GetOrDefault(BlobContainerNameAttribute.GetContainerName<TestContainer2>());
.GetOrDefaultConfiguration(BlobContainerNameAttribute.GetContainerName<TestContainer2>());
testContainer2Config.ShouldContainKeyAndValue("TestConfig2", "TestValue2");
}
}

@ -4,6 +4,9 @@ namespace Volo.Abp.BlobStoring
{
public abstract class AbpBlobStoringTestBase : AbpIntegratedTest<AbpBlobStoringTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}
}

@ -1,25 +1,42 @@
using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Volo.Abp.Autofac;
using Volo.Abp.BlobStoring.Fakes;
using Volo.Abp.BlobStoring.Providers;
using Volo.Abp.BlobStoring.TestObjects;
using Volo.Abp.Modularity;
namespace Volo.Abp.BlobStoring
{
[DependsOn(
typeof(AbpBlobStoringModule),
typeof(AbpTestBaseModule)
typeof(AbpTestBaseModule),
typeof(AbpAutofacModule)
)]
public class AbpBlobStoringTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IBlobProvider>(Substitute.For<FakeBlobProvider1>());
context.Services.AddSingleton<IBlobProvider>(Substitute.For<FakeBlobProvider2>());
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers
.ConfigureDefault(container =>
{
container["TestConfigDefault"] = "TestValueDefault";
container.ProviderType = typeof(FakeBlobProvider1);
})
.Configure<TestContainer1>(container =>
{
container["TestConfig1"] = "TestValue1";
container.ProviderType = typeof(FakeBlobProvider1);
})
.Configure<TestContainer2>(container =>
{
container["TestConfig2"] = "TestValue2";
container.ProviderType = typeof(FakeBlobProvider2);
});
});
}

@ -0,0 +1,78 @@
using System.Threading.Tasks;
using NSubstitute;
using Shouldly;
using Volo.Abp.BlobStoring.Fakes;
using Volo.Abp.BlobStoring.Providers;
using Volo.Abp.BlobStoring.TestObjects;
using Xunit;
namespace Volo.Abp.BlobStoring
{
public class BlobContainerFactory_Tests : AbpBlobStoringTestBase
{
private readonly IBlobContainerFactory _factory;
private readonly FakeProviders _fakeProviders;
public BlobContainerFactory_Tests()
{
_factory = GetRequiredService<IBlobContainerFactory>();
_fakeProviders = GetRequiredService<FakeProviders>();
}
[Fact]
public async Task Should_Create_Containers_With_Configured_Providers()
{
// TestContainer1 with FakeBlobProvider1
await _fakeProviders.Provider1
.DidNotReceiveWithAnyArgs()
.ExistsAsync(default);
await _factory
.Create<TestContainer1>()
.ExistsAsync("TestBlob1");
await _fakeProviders.Provider1
.Received(1)
.ExistsAsync(Arg.Is<BlobProviderExistsArgs>(args =>
args.ContainerName == BlobContainerNameAttribute.GetContainerName<TestContainer1>() &&
args.BlobName == "TestBlob1"
)
);
// TestContainer2 with FakeBlobProvider2
await _fakeProviders.Provider2
.DidNotReceiveWithAnyArgs()
.ExistsAsync(default);
await _factory
.Create<TestContainer2>()
.ExistsAsync("TestBlob2");
await _fakeProviders.Provider2
.Received(1)
.ExistsAsync(Arg.Is<BlobProviderExistsArgs>(args =>
args.ContainerName == BlobContainerNameAttribute.GetContainerName<TestContainer2>() &&
args.BlobName == "TestBlob2"
)
);
// TestContainer3 with FakeBlobProvider1 (default provider)
_fakeProviders.Provider1.ClearReceivedCalls();
await _factory
.Create<TestContainer3>()
.ExistsAsync("TestBlob3");
await _fakeProviders.Provider1
.Received(1)
.ExistsAsync(Arg.Is<BlobProviderExistsArgs>(t =>
t.ContainerName == BlobContainerNameAttribute.GetContainerName<TestContainer3>() &&
t.BlobName == "TestBlob3"
)
);
}
}
}

@ -1,4 +1,5 @@
using Shouldly;
using Volo.Abp.BlobStoring.TestObjects;
using Xunit;
namespace Volo.Abp.BlobStoring
@ -9,27 +10,16 @@ namespace Volo.Abp.BlobStoring
public void Should_Get_Specified_Name()
{
BlobContainerNameAttribute
.GetContainerName<MyContainerType2>()
.ShouldBe("ContName2");
.GetContainerName<TestContainer2>()
.ShouldBe("Test2");
}
[Fact]
public void Should_Get_Full_Class_Name_If_Not_Specified()
{
BlobContainerNameAttribute
.GetContainerName<MyContainerType1>()
.ShouldBe(typeof(MyContainerType1).FullName);
}
private class MyContainerType1
{
}
[BlobContainerName("ContName2")]
private class MyContainerType2
{
.GetContainerName<TestContainer1>()
.ShouldBe(typeof(TestContainer1).FullName);
}
}
}

@ -0,0 +1,34 @@
using System.IO;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring.Providers;
namespace Volo.Abp.BlobStoring.Fakes
{
public class FakeBlobProvider1 : IBlobProvider
{
public virtual Task SaveAsync(BlobProviderSaveArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<bool> DeleteAsync(BlobProviderDeleteArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<bool> ExistsAsync(BlobProviderExistsArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<Stream> GetAsync(BlobProviderGetArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
{
throw new System.NotImplementedException();
}
}
}

@ -0,0 +1,34 @@
using System.IO;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring.Providers;
namespace Volo.Abp.BlobStoring.Fakes
{
public class FakeBlobProvider2 : IBlobProvider
{
public virtual Task SaveAsync(BlobProviderSaveArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<bool> DeleteAsync(BlobProviderDeleteArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<bool> ExistsAsync(BlobProviderExistsArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<Stream> GetAsync(BlobProviderGetArgs args)
{
throw new System.NotImplementedException();
}
public virtual Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
{
throw new System.NotImplementedException();
}
}
}

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.BlobStoring.Providers;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BlobStoring.Fakes
{
public class FakeProviders : ISingletonDependency
{
public FakeBlobProvider1 Provider1 { get; }
public FakeBlobProvider2 Provider2 { get; }
public FakeProviders(IEnumerable<IBlobProvider> providers)
{
Provider1 = providers.OfType<FakeBlobProvider1>().Single();
Provider2 = providers.OfType<FakeBlobProvider2>().Single();
}
}
}

@ -1,12 +0,0 @@
namespace Volo.Abp.BlobStoring
{
public class TestContainer1
{
}
public class TestContainer2
{
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.BlobStoring.TestObjects
{
public class TestContainer1
{
}
}

@ -0,0 +1,8 @@
namespace Volo.Abp.BlobStoring.TestObjects
{
[BlobContainerName("Test2")]
public class TestContainer2
{
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.BlobStoring.TestObjects
{
public class TestContainer3
{
}
}
Loading…
Cancel
Save