StreamStore

Asynchronous event sourcing

View on GitHub

Storage

Storage is a persistence layer for the StreamStore library.

Create your own storage implementation

Implement your own storage from scratch

To create your own storage implementation, you need to implement the following interfaces:

Single tenant mode

Multitenant mode

Storage class diagram

However, there is much easier way to do so.

Use base implementations

You can use base implementations of the interfaces provided by StreamStore.Storage package.

For to do so, you need to create implementation of the following abstract classes:

After that you can register your storage implementation in the DI container by creating extension method for IServiceCollection and using existing extensions.

Example: SQLite storage service collection extensions ```csharp public static class ServiceCollectionExtension { public static IServiceCollection UseSqlite(this IServiceCollection services) { services.ConfigurePersistence(new StorageConfigurator(SqliteConfiguration.DefaultConfiguration)); return services; } public static IServiceCollection UseSqlite(this IServiceCollection services, IConfiguration configuration) { configuration.ThrowIfNull(nameof(configuration)); services.ConfigurePersistence( new StorageConfigurator( SqlStorageConfigurationBuilder.ReadFromConfig( configuration, SqliteConfiguration.ConfigurationSection, SqliteConfiguration.DefaultConfiguration))); return services; } public static IServiceCollection UseSqlite(this IServiceCollection services, Action configure) { configure.ThrowIfNull(nameof(configure)); services.ConfigurePersistence( new StorageConfigurator( new SqlStorageConfigurationBuilder( SqliteConfiguration.DefaultConfiguration, configure).Build())); return services; } public static IServiceCollection UseSqliteWithMultitenancy(this IServiceCollection services, SqlStorageConfiguration defaultConfig, Action configure) { configure.ThrowIfNull(nameof(defaultConfig)); configure.ThrowIfNull(nameof(configure)); services.ConfigurePersistenceMultitenancy( new StorageConfigurator(defaultConfig), new MultitenancyConfigurator(configure)); return services; } public static IServiceCollection UseSqliteWithMultitenancy(this IServiceCollection services, Action configure) { return services.UseSqliteWithMultitenancy(SqliteConfiguration.DefaultConfiguration, configure); } } ``` </details> ## Considerations - To implement your own storage you do not need StreamStore package, all necessary interfaces are located in [StreamStore.Storage.Contracts](https://www.nuget.org/packages/StreamStore.Contracts/) and base implementations in [StreamStore.Storage](https://www.nuget.org/packages/StreamStore.Storage/) package. - _You can register your own storage implementation in the DI container using any kind of lifetime (i.e. Singleton, Transient, Scoped, etc.)_ However, if you register it as a singleton, you should be aware that it should be thread-safe and preferably stateless. - _Solution already provides optimistic concurrency and event duplication control mechanisms, as a **pre-check** during stream opening_. However, if you need consistency guaranteed, you should implement your own mechanisms as a part of [IStreamWriter] implementation. For instance, you can use a transaction mechanism supported by `ACID compliant DBMS`. - _Get and Delete operations must be implemented as idempotent by their nature._ [IStreamWriter]:../src/StreamStore.Storage.Contracts/Storage/IStreamWriter.cs [IStreamStorage]:../src/StreamStore.Storage.Contracts/Storage/IStreamStorage.cs [ISchemaProvisioner]:../src/StreamStore.Storage.Contracts/Provisioning/ISchemaProvisioner.cs [ITenantStreamStorageProvider]:../src/StreamStore.Storage.Contracts/Multitenancy/ITenantStreamStorageProvider.cs [ITenantSchemaProvisionerFactory]:../src/StreamStore.Storage.Contracts/Multitenancy/ITenantSchemaProvisionerFactory.cs [StorageConfiguratorBase]:../src/StreamStore.Storage/Configuration/StorageConfiguratorBase.cs [MultitenancyConfiguratorBase]:../src/StreamStore.Storage/Configuration/MultitenancyConfiguratorBase.cs