doc/WebSite/BLOB-Storing.md
Storing binary objects a.k.a. BLOBs is a feature most modern apps need. ASP.NET Boilerplate provides an infrastructure for storing BLOBs. BLOBs can be stored in a file system, database or on a cloud provider.
ASP.NET Boilerplate provides an abstraction to work with BLOBs and provides some pre-built storage providers that you can easily integrate to. Having such an abstraction has some benefits;
ASP.NET Boilerplate offers BLOB providers below out of the box;
Abp.BlobStoring is the main package that defines the BLOB storing services. You can use this package to use the BLOB Storing system without depending a specific storage provider.
Install the Abp.BlobStoring NuGet package to your project and add [DependsOn(typeof(AbpBlobStoringModule))] to the ABP module class inside your project.
IBlobContainer is the main interface to read and write BLOBs. An application may have multiple containers and each container can be separately configured. But, there is a default container that can be simply used by injecting the IBlobContainer.
Example: Simply read and write bytes of a named BLOB;
namespace DemoApp
{
public class MyService : ITransientDependency
{
private readonly IBlobContainer _blobContainer;
public MyService(IBlobContainer blobContainer)
{
_blobContainer = blobContainer;
}
public async Task SaveBytesAsync(byte[] bytes)
{
await _blobContainer.SaveAsync("sample-blob", bytes);
}
public async Task<byte[]> GetBytesAsync()
{
return await _blobContainer.GetAllBytesOrNullAsync("sample-blob");
}
}
}
This service saves the given bytes with the sample-blob name and then gets the previously saved bytes with the same name.
IBlobContainer can work with Stream and byte[] objects, which will be detailed in the next sections.
SaveAsync method is used to save a new BLOB or replace an existing BLOB. SaveAsync gets the following parameters:
GetAsync: Only gets a BLOB name and returns a Stream object that can be used to read the BLOB content. Always dispose the stream after using it. This method throws exception, if it can not find the BLOB with the given name.GetOrNullAsync: In opposite to the GetAsync method, this one returns null if there is no BLOB found with the given name.GetAllBytesAsync: Returns a byte[] instead of a Stream. Still throws exception if can not find the BLOB with the given name.GetAllBytesOrNullAsync: In opposite to the GetAllBytesAsync method, this one returns null if there is no BLOB found with the given name.DeleteAsync method gets a BLOB name and deletes the BLOB data. It doesn't throw any exception if given BLOB was not found. Instead, it returns a bool indicating that the BLOB was actually deleted or not, if you care about it.
ExistsAsync method simply checks if there is a BLOB in the container with the given name.Typed BLOB container system is a way of creating and managing multiple containers in an application;
To create a typed container, you need to create a simple class decorated with the BlobContainerName attribute:
using Volo.Abp.BlobStoring;
namespace DemoApp
{
[BlobContainerName("profile-pictures")]
public class ProfilePictureContainer
{
}
}
Once you create the container class, you can inject IBlobContainer<T> for your container type.
Example:
public class ProfileAppService : ApplicationService
{
private readonly IBlobContainer<ProfilePictureContainer> _blobContainer;
public ProfileAppService(IBlobContainer<ProfilePictureContainer> blobContainer)
{
_blobContainer = blobContainer;
}
public async Task SaveProfilePictureAsync(byte[] bytes)
{
var blobName = AbpSession.ToUserIdentifier().ToString();
await _blobContainer.SaveAsync(blobName, bytes);
}
public async Task<byte[]> GetProfilePictureAsync()
{
var blobName = AbpSession.ToUserIdentifier().ToString();
return await _blobContainer.GetAllBytesOrNullAsync(blobName);
}
}
If you don't use the generic argument and directly inject the IBlobContainer (as explained before), you get the default container. Another way of injecting the default container is using IBlobContainer<DefaultContainer>, which returns exactly the same container.
The name of the default container is default.
Typed containers are just shortcuts for named containers. You can inject and use the IBlobContainerFactory to get a BLOB container by its name:
public class ProfileAppService : ApplicationService
{
private readonly IBlobContainer _blobContainer;
public ProfileAppService(IBlobContainerFactory blobContainerFactory)
{
_blobContainer = blobContainerFactory.Create("profile-pictures");
}
//...
}
IBlobContainerFactory is the service that is used to create the BLOB containers. One example was shown above.
Example: Create a container by name
var blobContainer = blobContainerFactory.Create("profile-pictures");
Example: Create a container by type
var blobContainer = blobContainerFactory.Create<ProfilePictureContainer>();