mirror of https://github.com/abpframework/abp.git
15 changed files with 244 additions and 4 deletions
@ -0,0 +1,35 @@ |
|||
# BLOB Storing Memory Provider |
|||
|
|||
Memory Storage Provider is used to store BLOBs in the memory. This is mainly used for unit testing purposes. |
|||
|
|||
> Read the [BLOB Storing document](../blob-storing) to understand how to use the BLOB storing system. This document only covers how to configure containers to use the memory. |
|||
|
|||
## Installation |
|||
|
|||
Use the ABP CLI to add [Volo.Abp.BlobStoring.Memory](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Memory) NuGet package to your project: |
|||
|
|||
* Install the [ABP CLI](../../../cli) if you haven't installed before. |
|||
* Open a command line (terminal) in the directory of the `.csproj` file you want to add the `Volo.Abp.BlobStoring.Memory` package. |
|||
* Run `abp add-package Volo.Abp.BlobStoring.Memory` command. |
|||
|
|||
If you want to do it manually, install the [Volo.Abp.BlobStoring.Memory](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Memory) NuGet package to your project and add `[DependsOn(typeof(AbpBlobStoringMemoryModule))]` to the [ABP module](../../architecture/modularity/basics.md) class inside your project. |
|||
|
|||
## Configuration |
|||
|
|||
Configuration is done in the `ConfigureServices` method of your [module](../../architecture/modularity/basics.md) class, as explained in the [BLOB Storing document](../blob-storing). |
|||
|
|||
**Example: Configure to use the Memory storage provider by default** |
|||
|
|||
````csharp |
|||
Configure<AbpBlobStoringOptions>(options => |
|||
{ |
|||
options.Containers.ConfigureDefault(container => |
|||
{ |
|||
container.UseMemory(); |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
`UseMemory` extension method is used to set the Memory Provider for a container. |
|||
|
|||
> See the [BLOB Storing document](../blob-storing) to learn how to configure this provider for a specific container. |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -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> |
|||
@ -0,0 +1,23 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks> |
|||
<Nullable>enable</Nullable> |
|||
<WarningsAsErrors>Nullable</WarningsAsErrors> |
|||
<AssemblyName>Volo.Abp.BlobStoring.Memory</AssemblyName> |
|||
<PackageId>Volo.Abp.BlobStoring.Memory</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.BlobStoring.Memory; |
|||
|
|||
[DependsOn(typeof(AbpBlobStoringModule))] |
|||
public class AbpBlobStoringMemoryModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace Volo.Abp.BlobStoring.Memory; |
|||
|
|||
public static class MemoryBlobContainerConfigurationExtensions |
|||
{ |
|||
public static BlobContainerConfiguration UseMemory(this BlobContainerConfiguration containerConfiguration) |
|||
{ |
|||
containerConfiguration.ProviderType = typeof(MemoryBlobProvider); |
|||
return containerConfiguration; |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
using System.Collections.Concurrent; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace Volo.Abp.BlobStoring.Memory; |
|||
|
|||
public class MemoryBlobProvider : BlobProviderBase, ITransientDependency |
|||
{ |
|||
protected ConcurrentDictionary<string, byte[]> MemoryStore { get; } |
|||
|
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
|
|||
public MemoryBlobProvider(ICurrentTenant currentTenant) |
|||
{ |
|||
MemoryStore = new ConcurrentDictionary<string, byte[]>(); |
|||
|
|||
CurrentTenant = currentTenant; |
|||
} |
|||
|
|||
public override async Task SaveAsync(BlobProviderSaveArgs args) |
|||
{ |
|||
var cacheKey = GetCacheKey(args); |
|||
|
|||
using var buffer = new MemoryStream(); |
|||
await args.BlobStream.CopyToAsync(buffer); |
|||
var bytes = buffer.ToArray(); |
|||
|
|||
if (!args.OverrideExisting) |
|||
{ |
|||
if (!MemoryStore.TryAdd(cacheKey, bytes)) |
|||
{ |
|||
throw new BlobAlreadyExistsException( |
|||
$"Saving BLOB '{args.BlobName}' does already exists in the container '{args.ContainerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
MemoryStore.AddOrUpdate(cacheKey, bytes, (_, __) => bytes); |
|||
} |
|||
} |
|||
|
|||
public override Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
|||
{ |
|||
return Task.FromResult(MemoryStore.TryRemove(GetCacheKey(args), out _)); |
|||
} |
|||
|
|||
public override Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
|||
{ |
|||
return Task.FromResult(MemoryStore.ContainsKey(GetCacheKey(args))); |
|||
} |
|||
|
|||
public override Task<Stream?> GetOrNullAsync(BlobProviderGetArgs args) |
|||
{ |
|||
return MemoryStore.TryGetValue(GetCacheKey(args), out var bytes) |
|||
? Task.FromResult<Stream?>(new MemoryStream(bytes, writable: false)) |
|||
: Task.FromResult<Stream?>(null); |
|||
} |
|||
|
|||
protected virtual string GetCacheKey(BlobProviderArgs args) |
|||
{ |
|||
return $"{CurrentTenant.Id}_{args.BlobName}_{args.ContainerName}"; |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.test.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net10.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.BlobStoring.Memory\Volo.Abp.BlobStoring.Memory.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
|||
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" /> |
|||
<ProjectReference Include="..\Volo.Abp.BlobStoring.Tests\Volo.Abp.BlobStoring.Tests.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,21 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.BlobStoring.Memory; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpBlobStoringMemoryModule), |
|||
typeof(AbpBlobStoringTestModule) |
|||
)] |
|||
public class AbpBlobStoringMemoryTestModule : AbpModule |
|||
{ |
|||
public override void PostConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpBlobStoringOptions>(options => |
|||
{ |
|||
options.Containers.ConfigureAll((containerName, containerConfiguration) => |
|||
{ |
|||
containerConfiguration.UseMemory(); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
namespace Volo.Abp.BlobStoring.Memory; |
|||
|
|||
public class MemoryBlobContainer_Tests : BlobContainer_Tests<AbpBlobStoringMemoryTestModule> |
|||
{ |
|||
|
|||
} |
|||
@ -1,14 +1,26 @@ |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.BlobStoring.Memory; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Docs.Admin; |
|||
|
|||
namespace Volo.Docs |
|||
{ |
|||
[DependsOn( |
|||
typeof(DocsAdminApplicationModule), |
|||
typeof(DocsDomainTestModule) |
|||
typeof(DocsDomainTestModule), |
|||
typeof(AbpBlobStoringMemoryModule) |
|||
)] |
|||
public class DocsAdminApplicationTestModule : AbpModule |
|||
{ |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpBlobStoringOptions>(options => |
|||
{ |
|||
options.Containers.ConfigureDefault(container => |
|||
{ |
|||
container.UseMemory(); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue