BLOB Storing: Creating a Custom Provider

This document explains how you can create a new storage provider for the BLOB storing system with an example.

Read the BLOB Storing document to understand how to use the BLOB storing system. This document only covers how to create a new storage provider.

Example Implementation

The first step is to create a class implements the IBlobProvider interface or inherit from the BlobProviderBase abstract class.

using System.IO;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.DependencyInjection;

namespace AbpDemo
{
    public class MyCustomBlobProvider : BlobProviderBase, ITransientDependency
    {
        public override Task SaveAsync(BlobProviderSaveArgs args)
        {
            //TODO...
        }

        public override Task<bool> DeleteAsync(BlobProviderDeleteArgs args)
        {
            //TODO...
        }

        public override Task<bool> ExistsAsync(BlobProviderExistsArgs args)
        {
            //TODO...
        }

        public override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
        {
            //TODO...
        }
    }
}
  • MyCustomBlobProvider inherits from the BlobProviderBase and overrides the abstract methods. The actual implementation is up to you.
  • Implementing ITransientDependency registers this class to the Dependency Injection system as a transient service.

Notice: Naming conventions are important. If your class name doesn't end with BlobProvider, you must manually register/expose your service for the IBlobProvider.

That's all. Now, you can configure containers (inside the ConfigureServices method of your module) to use the MyCustomBlobProvider class:

Configure<AbpBlobStoringOptions>(options =>
{
    options.Containers.ConfigureDefault(container =>
    {
        container.ProviderType = typeof(MyCustomBlobProvider);
    });
});

See the BLOB Storing document if you want to configure a specific container.

BlobContainerConfiguration Extension Method

If you want to provide a simpler configuration, create an extension method for the BlobContainerConfiguration class:

public static class MyBlobContainerConfigurationExtensions
{
    public static BlobContainerConfiguration UseMyCustomBlobProvider(
        this BlobContainerConfiguration containerConfiguration)
    {
        containerConfiguration.ProviderType = typeof(MyCustomBlobProvider);
        return containerConfiguration;
    }
}

Then you can configure containers easier using the extension method:

Configure<AbpBlobStoringOptions>(options =>
{
    options.Containers.ConfigureDefault(container =>
    {
        container.UseMyCustomBlobProvider();
    });
});

Extra Configuration Options

BlobContainerConfiguration allows to add/remove provider specific configuration objects. If your provider needs to additional configuration, you can create a wrapper class to the BlobContainerConfiguration for a type-safe configuration option:

    public class MyCustomBlobProviderConfiguration
    {
        public string MyOption1
        {
            get => _containerConfiguration
                .GetConfiguration<string>("MyCustomBlobProvider.MyOption1");
            set => _containerConfiguration
                .SetConfiguration("MyCustomBlobProvider.MyOption1", value);
        }

        private readonly BlobContainerConfiguration _containerConfiguration;

        public MyCustomBlobProviderConfiguration(
            BlobContainerConfiguration containerConfiguration)
        {
            _containerConfiguration = containerConfiguration;
        }
    }

Then you can change the MyBlobContainerConfigurationExtensions class like that:

public static class MyBlobContainerConfigurationExtensions
{
    public static BlobContainerConfiguration UseMyCustomBlobProvider(
        this BlobContainerConfiguration containerConfiguration,
        Action<MyCustomBlobProviderConfiguration> configureAction)
    {
        containerConfiguration.ProviderType = typeof(MyCustomBlobProvider);
        
        configureAction.Invoke(
            new MyCustomBlobProviderConfiguration(containerConfiguration)
        );
        
        return containerConfiguration;
    }
    
    public static MyCustomBlobProviderConfiguration GetMyCustomBlobProviderConfiguration(
        this BlobContainerConfiguration containerConfiguration)
    {
        return new MyCustomBlobProviderConfiguration(containerConfiguration);
    }
}
  • Added an action parameter to the UseMyCustomBlobProvider method to allow developers to set the additional options.
  • Added a new GetMyCustomBlobProviderConfiguration method to be used inside MyCustomBlobProvider class to obtain the configured values.

Then anyone can set the MyOption1 as shown below:

Configure<AbpBlobStoringOptions>(options =>
{
    options.Containers.ConfigureDefault(container =>
    {
        container.UseMyCustomBlobProvider(provider =>
        {
            provider.MyOption1 = "my value";
        });
    });
});

Finally, you can access to the extra options using the GetMyCustomBlobProviderConfiguration method:

public class MyCustomBlobProvider : BlobProviderBase, ITransientDependency
{
    public override Task SaveAsync(BlobProviderSaveArgs args)
    {
        var config = args.Configuration.GetMyCustomBlobProviderConfiguration();
        var value = config.MyOption1;
        
        //...
    }
}

Contribute?

If you create a new provider and you think it can be useful for other developers, please consider to contribute to the ABP Framework on GitHub.

In this document