Skip to content

2.6 Storage

Marjan Nikolovski edited this page Apr 9, 2021 · 1 revision

Purpose

Data storage is the recording (storing) of information (data) in a storage medium. DNA and RNA, handwriting, phonographic recording, magnetic tape, and optical discs are all examples of storage media. Recording is accomplished by virtually any form of energy. Electronic data storage requires electrical power to store and retrieve data.

Data storage in a digital, machine-readable medium is sometimes called digital data. Computer data storage is one of the core functions of a general purpose computer. Electronic documents can be stored in much less space than paper documents. Barcodes and magnetic ink character recognition (MICR) are two ways of recording machine-readable data on paper.

Signals offers multiple implementations for the Storage aspect out of the box:

  • Signals.Aspects.Storage.File
  • Signals.Aspects.Storage.Database
  • Signals.Aspects.Storage.Azure

Only one implementation can be active at a time.

How to use

When we implement any type of process a storage provider is automatically injected in the process context.

public class MyProcess : BusinessProcess<VoidResult>
{
    /// <summary>
    /// Authenticate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Auth()
    {
        return Ok();
    }

    /// <summary>
    /// Validate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Validate()
    {
        return Ok();
    }

    /// <summary>
    /// Handle process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Handle()
    {
        // store data through storage provider
        Task storeTask = Task.CompletedTask;

        // from disk
        storeTask = Context.Storage.Store("path/to/destination", "my_data", "path/to/source/data.dat");
        storeTask.Wait();

        // from stream
        Stream myStream = new Stream();
        storeTask = Context.Storage.Store("path/to/destination", "my_data", myStream);
        storeTask.Wait();

        // from byte array
        byte[] myBytes = new byte[] { 1, 2, 3 };
        storeTask = Context.Storage.Store("path/to/destination", "my_data", myBytes);
        storeTask.Wait();


        // get data through storage provider
        Stream data = Context.Storage.Get("path/to/data", "my_data");


        // remove data from storage provider
        Task removeTask = Context.Storage.Remove("path/to/data", "my_data");
        removeTask.Wait();

        return Ok();
    }
}

Other more manual way of using the storage is through the IStorageProvider instance.

public async Task StoreData(string sourceFilePath, string destinationFolder, string file)
{
    var storageProvider = SystemBootstrapper.GetInstance<IStorageProvider>();
    Task task = storageProvider.Store(destinationFolder, file, sourceFilePath);

    return await task;
}
public Stream GetData(string folder, string file)
{
    var storageProvider = SystemBootstrapper.GetInstance<IStorageProvider>();
    Stream data = storageProvider.Get(folder, file);

    return data;
}
public Stream RemoveData(string folder, string file)
{
    var storageProvider = SystemBootstrapper.GetInstance<IStorageProvider>();
    Task task = storageProvider.Remove(folder, file);

    return await task;
}

Configuration

We configure the storage aspect by using an instance of Signals.Aspects.Storage.Configurations.IStorageConfiguration which we pass in the ApplicationBootstrapConfiguration instance (web or background) at startup.

Properties explanation

AzureStorageConfiguration

  • ConnectionString: Azure connection string
  • Encrypt: Should stored files be encrypted
  • CertificatePath: Certificate path for ecntrypting files
  • CertificatePassword: Certificate password for ecntrypting files
  • CertificateThumbprint: Certificate thumbprint for ecntrypting files

DatabaseStorageConfiguration

  • ConnectionString: Database connection string
  • TableName: File storage table name. Default Storage
  • Encrypt: Should stored files be encrypted
  • CertificatePath: Certificate path for ecntrypting files
  • CertificatePassword: Certificate password for ecntrypting files
  • CertificateThumbprint: Certificate thumbprint for ecntrypting files

FileStorageConfiguration

  • RootPath: Root directory path where all files are stored. Default Environment.CurrentDirectory
  • Encrypt: Should stored files be encrypted
  • CertificatePath: Certificate path for ecntrypting files
  • CertificatePassword: Certificate password for ecntrypting files
  • CertificateThumbprint: Certificate thumbprint for ecntrypting files

Examples

Using Signals.Aspects.Storage.Azure

AzureStorageConfiguration

services
    .AddSignals(config =>
    {
        config.StorageConfiguration = new AzureStorageConfiguration
        {
            ConnectionString = myAzureConnectionString,
            Encrypt = true,
            CertificatePath = "/path/to/certificate",
            CertificatePassword = "my.password",
            CertificateThumbprint = "my.certificate.thumbprint"
        };
    });

Using Signals.Aspects.Storage.Database

DatabaseStorageConfiguration

services
    .AddSignals(config =>
    {
        config.StorageConfiguration = new DatabaseStorageConfiguration
        {
            ConnectionString = myConnectionString,
            TableName = "StorageTable",
            Encrypt = true,
            CertificatePath = "/path/to/certificate",
            CertificatePassword = "my.password",
            CertificateThumbprint = "my.certificate.thumbprint"
        };
    });

Using Signals.Aspects.Storage.File

FileStorageConfiguration

services
    .AddSignals(config =>
    {
        config.StorageConfiguration = new FileStorageConfiguration
        {
            RootPath = "/path/to/storage",
            Encrypt = true,
            CertificatePath = "/path/to/certificate",
            CertificatePassword = "my.password",
            CertificateThumbprint = "my.certificate.thumbprint"
        };
    });

Extending storage

  1. Install package Signals.Aspects.Storage
  2. Create class with implementation of Signals.Aspects.Storage.Configurations.IStorageConfiguration
/// <summary>
/// Storage configuration contract
/// </summary>
public class MyStorageConfiguration : IStorageConfiguration
{
    /// <summary>
    /// Custom property
    /// </summary>
    public string MyProperty { get; set; }

    /// <summary>
    /// Should stored files be encrypted
    /// </summary>
    public bool Encrypt { get; set; }

    /// <summary>
    /// Certificate path for ecntrypting files
    /// </summary>
    public string CertificatePath { get; set; }

    /// <summary>
    /// Certificate password for ecntrypting files
    /// </summary>
    public string CertificatePassword { get; set; }

    /// <summary>
    /// Certificate thumbprint for ecntrypting files
    /// </summary>
    public string CertificateThumbprint { get; set; }
}
  1. Create class with implementation of Signals.Aspects.Storage.IStorageProvider
/// <summary>
/// Storage contract
/// </summary>
public class MyStorageProvider : IStorageProvider
{
    private MyStorageConfiguration _configuraiton;

    /// <summary>
    /// CTOR
    /// </summary>
    /// <param name="configuraiton"></param>
    public MyStorageProvider(MyStorageConfiguration configuraiton)
    {
        _configuraiton = configuraiton;
    }

    /// <summary>
    /// Retrieve stored file
    /// </summary>
    /// <param name="path"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    Stream Get(string path, string name);

    /// <summary>
    /// Remove stored file
    /// </summary>
    /// <param name="path"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    async Task Remove(string path, string name);

    /// <summary>
    /// Store file from stream
    /// </summary>
    /// <param name="path"></param>
    /// <param name="name"></param>
    /// <param name="inStream"></param>
    /// <returns></returns>
    async Task Store(string path, string name, Stream inStream);

    /// <summary>
    /// Store file as bytes
    /// </summary>
    /// <param name="path"></param>
    /// <param name="name"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    async Task Store(string path, string name, byte[] data);

    /// <summary>
    /// Store file from location path
    /// </summary>
    /// <param name="path"></param>
    /// <param name="name"></param>
    /// <param name="sourcePath"></param>
    /// <returns></returns>
    async Task Store(string path, string name, string sourcePath);
}
  1. Use our implementation of IStorageConfiguration when configuring our application
public static IServiceProvider AddSignals(this IServiceCollection services)
{
    services
        .AddSignals(config =>
        {
            config.StorageConfiguration = new MyStorageConfiguration
            {
                MyProperty = "my_value"
                Encrypt = true,
                CertificatePath = "/path/to/certificate",
                CertificatePassword = "my.password",
                CertificateThumbprint = "my.certificate.thumbprint"
            };
        });
}
Clone this wiki locally